← Documents Documentation/dev-tools/kunit/usage.rst GitHub 원문 ↗

Linux 6.18.37 · Dev Tools

Writing Tests

KUnit case와 suite, fake dependency, parameterized test, resource lifetime, cleanup, static function과 fake device testing pattern을 설명합니다.

Source pathDocumentation/dev-tools/kunit/usage.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

usage.rst:1-1214

KUnit test는 짧은 case에 expectation과 assertion을 배치하고 suite lifecycle로 setup과 teardown을 관리합니다. Unit boundary를 유지하려면 function pointer 기반 class와 fake implementation으로 느리거나 hardware-dependent한 dependency를 대체합니다.

여러 input은 table-driven 또는 parameterized test로 다루며 parent context에 shared resource를 둡니다. KUnit-managed allocation과 deferred action은 조기 assertion failure에도 cleanup을 보장하고, visibility macro, current-test API와 fake device helper는 kernel 내부 code를 production 동작에 미치는 영향 없이 검사하도록 돕습니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 Writing Tests
4 =============
5
6 Test Cases
7 ----------
8
9 The fundamental unit in KUnit is the test case. A test case is a function with
10 the signature ``void (*)(struct kunit *test)``. It calls the function under test
11 and then sets *expectations* for what should happen. For example:
12
13 .. code-block:: c
14
15 void example_test_success(struct kunit *test)
16 {
17 }
18
19 void example_test_failure(struct kunit *test)
20 {
21 KUNIT_FAIL(test, "This test never passes.");
22 }
23
24 In the above example, ``example_test_success`` always passes because it does
25 nothing; no expectations are set, and therefore all expectations pass. On the
26 other hand ``example_test_failure`` always fails because it calls ``KUNIT_FAIL``,
27 which is a special expectation that logs a message and causes the test case to
28 fail.
29
30 Expectations
31 ~~~~~~~~~~~~
32 An *expectation* specifies that we expect a piece of code to do something in a
33 test. An expectation is called like a function. A test is made by setting
34 expectations about the behavior of a piece of code under test. When one or more
35 expectations fail, the test case fails and information about the failure is
36 logged. For example:
37
38 .. code-block:: c
39
40 void add_test_basic(struct kunit *test)
41 {
42 KUNIT_EXPECT_EQ(test, 1, add(1, 0));
43 KUNIT_EXPECT_EQ(test, 2, add(1, 1));
44 }
45
46 In the above example, ``add_test_basic`` makes a number of assertions about the
47 behavior of a function called ``add``. The first parameter is always of type
48 ``struct kunit *``, which contains information about the current test context.
49 The second parameter, in this case, is what the value is expected to be. The
50 last value is what the value actually is. If ``add`` passes all of these
51 expectations, the test case, ``add_test_basic`` will pass; if any one of these
52 expectations fails, the test case will fail.
53
54 A test case *fails* when any expectation is violated; however, the test will
55 continue to run, and try other expectations until the test case ends or is
56 otherwise terminated. This is as opposed to *assertions* which are discussed
57 later.
58
59 To learn about more KUnit expectations, see Documentation/dev-tools/kunit/api/test.rst.
60
61 .. note::
62 A single test case should be short, easy to understand, and focused on a
63 single behavior.
64
65 For example, if we want to rigorously test the ``add`` function above, create
66 additional tests cases which would test each property that an ``add`` function
67 should have as shown below:
68
69 .. code-block:: c
70
71 void add_test_basic(struct kunit *test)
72 {
73 KUNIT_EXPECT_EQ(test, 1, add(1, 0));
74 KUNIT_EXPECT_EQ(test, 2, add(1, 1));
75 }
76
77 void add_test_negative(struct kunit *test)
78 {
79 KUNIT_EXPECT_EQ(test, 0, add(-1, 1));
80 }
81
82 void add_test_max(struct kunit *test)
83 {
84 KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX));
85 KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN));
86 }
87
88 void add_test_overflow(struct kunit *test)
89 {
90 KUNIT_EXPECT_EQ(test, INT_MIN, add(INT_MAX, 1));
91 }
92
93 Assertions
94 ~~~~~~~~~~
95
96 An assertion is like an expectation, except that the assertion immediately
97 terminates the test case if the condition is not satisfied. For example:
98
99 .. code-block:: c
100
101 static void test_sort(struct kunit *test)
102 {
103 int *a, i, r = 1;
104 a = kunit_kmalloc_array(test, TEST_LEN, sizeof(*a), GFP_KERNEL);
105 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, a);
106 for (i = 0; i < TEST_LEN; i++) {
107 r = (r * 725861) % 6599;
108 a[i] = r;
109 }
110 sort(a, TEST_LEN, sizeof(*a), cmpint, NULL);
111 for (i = 0; i < TEST_LEN-1; i++)
112 KUNIT_EXPECT_LE(test, a[i], a[i + 1]);
113 }
114
115 In this example, we need to be able to allocate an array to test the ``sort()``
116 function. So we use ``KUNIT_ASSERT_NOT_ERR_OR_NULL()`` to abort the test if
117 there's an allocation error.
118
119 .. note::
120 In other test frameworks, ``ASSERT`` macros are often implemented by calling
121 ``return`` so they only work from the test function. In KUnit, we stop the
122 current kthread on failure, so you can call them from anywhere.
123
124 .. note::
125 Warning: There is an exception to the above rule. You shouldn't use assertions
126 in the suite's exit() function, or in the free function for a resource. These
127 run when a test is shutting down, and an assertion here prevents further
128 cleanup code from running, potentially leading to a memory leak.
129
130 Customizing error messages
131 --------------------------
132
133 Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG``
134 variant. These take a format string and arguments to provide additional
135 context to the automatically generated error messages.
136
137 .. code-block:: c
138
139 char some_str[41];
140 generate_sha1_hex_string(some_str);
141
142 /* Before. Not easy to tell why the test failed. */
143 KUNIT_EXPECT_EQ(test, strlen(some_str), 40);
144
145 /* After. Now we see the offending string. */
146 KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);
147
148 Alternatively, one can take full control over the error message by using
149 ``KUNIT_FAIL()``, e.g.
150
151 .. code-block:: c
152
153 /* Before */
154 KUNIT_EXPECT_EQ(test, some_setup_function(), 0);
155
156 /* After: full control over the failure message. */
157 if (some_setup_function())
158 KUNIT_FAIL(test, "Failed to setup thing for testing");
159
160
161 Test Suites
162 ~~~~~~~~~~~
163
164 We need many test cases covering all the unit's behaviors. It is common to have
165 many similar tests. In order to reduce duplication in these closely related
166 tests, most unit testing frameworks (including KUnit) provide the concept of a
167 *test suite*. A test suite is a collection of test cases for a unit of code
168 with optional setup and teardown functions that run before/after the whole
169 suite and/or every test case.
170
171 .. note::
172 A test case will only run if it is associated with a test suite.
173
174 For example:
175
176 .. code-block:: c
177
178 static struct kunit_case example_test_cases[] = {
179 KUNIT_CASE(example_test_foo),
180 KUNIT_CASE(example_test_bar),
181 KUNIT_CASE(example_test_baz),
182 {}
183 };
184
185 static struct kunit_suite example_test_suite = {
186 .name = "example",
187 .init = example_test_init,
188 .exit = example_test_exit,
189 .suite_init = example_suite_init,
190 .suite_exit = example_suite_exit,
191 .test_cases = example_test_cases,
192 };
193 kunit_test_suite(example_test_suite);
194
195 In the above example, the test suite ``example_test_suite`` would first run
196 ``example_suite_init``, then run the test cases ``example_test_foo``,
197 ``example_test_bar``, and ``example_test_baz``. Each would have
198 ``example_test_init`` called immediately before it and ``example_test_exit``
199 called immediately after it. Finally, ``example_suite_exit`` would be called
200 after everything else. ``kunit_test_suite(example_test_suite)`` registers the
201 test suite with the KUnit test framework.
202
203 .. note::
204 The ``exit`` and ``suite_exit`` functions will run even if ``init`` or
205 ``suite_init`` fail. Make sure that they can handle any inconsistent
206 state which may result from ``init`` or ``suite_init`` encountering errors
207 or exiting early.
208
209 ``kunit_test_suite(...)`` is a macro which tells the linker to put the
210 specified test suite in a special linker section so that it can be run by KUnit
211 either after ``late_init``, or when the test module is loaded (if the test was
212 built as a module).
213
214 For more information, see Documentation/dev-tools/kunit/api/test.rst.
215
216 .. _kunit-on-non-uml:
217
218 Writing Tests For Other Architectures
219 -------------------------------------
220
221 It is better to write tests that run on UML to tests that only run under a
222 particular architecture. It is better to write tests that run under QEMU or
223 another easy to obtain (and monetarily free) software environment to a specific
224 piece of hardware.
225
226 Nevertheless, there are still valid reasons to write a test that is architecture
227 or hardware specific. For example, we might want to test code that really
228 belongs in ``arch/some-arch/*``. Even so, try to write the test so that it does
229 not depend on physical hardware. Some of our test cases may not need hardware,
230 only few tests actually require the hardware to test it. When hardware is not
231 available, instead of disabling tests, we can skip them.
232
233 Now that we have narrowed down exactly what bits are hardware specific, the
234 actual procedure for writing and running the tests is same as writing normal
235 KUnit tests.
236
237 .. important::
238 We may have to reset hardware state. If this is not possible, we may only
239 be able to run one test case per invocation.
240
241 .. TODO([email protected]): Add an actual example of an architecture-
242 dependent KUnit test.
243
244 Common Patterns
245 ===============
246
247 Isolating Behavior
248 ------------------
249
250 Unit testing limits the amount of code under test to a single unit. It controls
251 what code gets run when the unit under test calls a function. Where a function
252 is exposed as part of an API such that the definition of that function can be
253 changed without affecting the rest of the code base. In the kernel, this comes
254 from two constructs: classes, which are structs that contain function pointers
255 provided by the implementer, and architecture-specific functions, which have
256 definitions selected at compile time.
257
258 Classes
259 ~~~~~~~
260
261 Classes are not a construct that is built into the C programming language;
262 however, it is an easily derived concept. Accordingly, in most cases, every
263 project that does not use a standardized object oriented library (like GNOME's
264 GObject) has their own slightly different way of doing object oriented
265 programming; the Linux kernel is no exception.
266
267 The central concept in kernel object oriented programming is the class. In the
268 kernel, a *class* is a struct that contains function pointers. This creates a
269 contract between *implementers* and *users* since it forces them to use the
270 same function signature without having to call the function directly. To be a
271 class, the function pointers must specify that a pointer to the class, known as
272 a *class handle*, be one of the parameters. Thus the member functions (also
273 known as *methods*) have access to member variables (also known as *fields*)
274 allowing the same implementation to have multiple *instances*.
275
276 A class can be *overridden* by *child classes* by embedding the *parent class*
277 in the child class. Then when the child class *method* is called, the child
278 implementation knows that the pointer passed to it is of a parent contained
279 within the child. Thus, the child can compute the pointer to itself because the
280 pointer to the parent is always a fixed offset from the pointer to the child.
281 This offset is the offset of the parent contained in the child struct. For
282 example:
283
284 .. code-block:: c
285
286 struct shape {
287 int (*area)(struct shape *this);
288 };
289
290 struct rectangle {
291 struct shape parent;
292 int length;
293 int width;
294 };
295
296 int rectangle_area(struct shape *this)
297 {
298 struct rectangle *self = container_of(this, struct rectangle, parent);
299
300 return self->length * self->width;
301 };
302
303 void rectangle_new(struct rectangle *self, int length, int width)
304 {
305 self->parent.area = rectangle_area;
306 self->length = length;
307 self->width = width;
308 }
309
310 In this example, computing the pointer to the child from the pointer to the
311 parent is done by ``container_of``.
312
313 Faking Classes
314 ~~~~~~~~~~~~~~
315
316 In order to unit test a piece of code that calls a method in a class, the
317 behavior of the method must be controllable, otherwise the test ceases to be a
318 unit test and becomes an integration test.
319
320 A fake class implements a piece of code that is different than what runs in a
321 production instance, but behaves identical from the standpoint of the callers.
322 This is done to replace a dependency that is hard to deal with, or is slow. For
323 example, implementing a fake EEPROM that stores the "contents" in an
324 internal buffer. Assume we have a class that represents an EEPROM:
325
326 .. code-block:: c
327
328 struct eeprom {
329 ssize_t (*read)(struct eeprom *this, size_t offset, char *buffer, size_t count);
330 ssize_t (*write)(struct eeprom *this, size_t offset, const char *buffer, size_t count);
331 };
332
333 And we want to test code that buffers writes to the EEPROM:
334
335 .. code-block:: c
336
337 struct eeprom_buffer {
338 ssize_t (*write)(struct eeprom_buffer *this, const char *buffer, size_t count);
339 int flush(struct eeprom_buffer *this);
340 size_t flush_count; /* Flushes when buffer exceeds flush_count. */
341 };
342
343 struct eeprom_buffer *new_eeprom_buffer(struct eeprom *eeprom);
344 void destroy_eeprom_buffer(struct eeprom *eeprom);
345
346 We can test this code by *faking out* the underlying EEPROM:
347
348 .. code-block:: c
349
350 struct fake_eeprom {
351 struct eeprom parent;
352 char contents[FAKE_EEPROM_CONTENTS_SIZE];
353 };
354
355 ssize_t fake_eeprom_read(struct eeprom *parent, size_t offset, char *buffer, size_t count)
356 {
357 struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);
358
359 count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset);
360 memcpy(buffer, this->contents + offset, count);
361
362 return count;
363 }
364
365 ssize_t fake_eeprom_write(struct eeprom *parent, size_t offset, const char *buffer, size_t count)
366 {
367 struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);
368
369 count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset);
370 memcpy(this->contents + offset, buffer, count);
371
372 return count;
373 }
374
375 void fake_eeprom_init(struct fake_eeprom *this)
376 {
377 this->parent.read = fake_eeprom_read;
378 this->parent.write = fake_eeprom_write;
379 memset(this->contents, 0, FAKE_EEPROM_CONTENTS_SIZE);
380 }
381
382 We can now use it to test ``struct eeprom_buffer``:
383
384 .. code-block:: c
385
386 struct eeprom_buffer_test {
387 struct fake_eeprom *fake_eeprom;
388 struct eeprom_buffer *eeprom_buffer;
389 };
390
391 static void eeprom_buffer_test_does_not_write_until_flush(struct kunit *test)
392 {
393 struct eeprom_buffer_test *ctx = test->priv;
394 struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
395 struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
396 char buffer[] = {0xff};
397
398 eeprom_buffer->flush_count = SIZE_MAX;
399
400 eeprom_buffer->write(eeprom_buffer, buffer, 1);
401 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);
402
403 eeprom_buffer->write(eeprom_buffer, buffer, 1);
404 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0);
405
406 eeprom_buffer->flush(eeprom_buffer);
407 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
408 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
409 }
410
411 static void eeprom_buffer_test_flushes_after_flush_count_met(struct kunit *test)
412 {
413 struct eeprom_buffer_test *ctx = test->priv;
414 struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
415 struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
416 char buffer[] = {0xff};
417
418 eeprom_buffer->flush_count = 2;
419
420 eeprom_buffer->write(eeprom_buffer, buffer, 1);
421 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);
422
423 eeprom_buffer->write(eeprom_buffer, buffer, 1);
424 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
425 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
426 }
427
428 static void eeprom_buffer_test_flushes_increments_of_flush_count(struct kunit *test)
429 {
430 struct eeprom_buffer_test *ctx = test->priv;
431 struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
432 struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
433 char buffer[] = {0xff, 0xff};
434
435 eeprom_buffer->flush_count = 2;
436
437 eeprom_buffer->write(eeprom_buffer, buffer, 1);
438 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);
439
440 eeprom_buffer->write(eeprom_buffer, buffer, 2);
441 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
442 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
443 /* Should have only flushed the first two bytes. */
444 KUNIT_EXPECT_EQ(test, fake_eeprom->contents[2], 0);
445 }
446
447 static int eeprom_buffer_test_init(struct kunit *test)
448 {
449 struct eeprom_buffer_test *ctx;
450
451 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
452 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
453
454 ctx->fake_eeprom = kunit_kzalloc(test, sizeof(*ctx->fake_eeprom), GFP_KERNEL);
455 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->fake_eeprom);
456 fake_eeprom_init(ctx->fake_eeprom);
457
458 ctx->eeprom_buffer = new_eeprom_buffer(&ctx->fake_eeprom->parent);
459 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->eeprom_buffer);
460
461 test->priv = ctx;
462
463 return 0;
464 }
465
466 static void eeprom_buffer_test_exit(struct kunit *test)
467 {
468 struct eeprom_buffer_test *ctx = test->priv;
469
470 destroy_eeprom_buffer(ctx->eeprom_buffer);
471 }
472
473 Testing Against Multiple Inputs
474 -------------------------------
475
476 Testing just a few inputs is not enough to ensure that the code works correctly,
477 for example: testing a hash function.
478
479 We can write a helper macro or function. The function is called for each input.
480 For example, to test ``sha1sum(1)``, we can write:
481
482 .. code-block:: c
483
484 #define TEST_SHA1(in, want) \
485 sha1sum(in, out); \
486 KUNIT_EXPECT_STREQ_MSG(test, out, want, "sha1sum(%s)", in);
487
488 char out[40];
489 TEST_SHA1("hello world", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
490 TEST_SHA1("hello world!", "430ce34d020724ed75a196dfc2ad67c77772d169");
491
492 Note the use of the ``_MSG`` version of ``KUNIT_EXPECT_STREQ`` to print a more
493 detailed error and make the assertions clearer within the helper macros.
494
495 The ``_MSG`` variants are useful when the same expectation is called multiple
496 times (in a loop or helper function) and thus the line number is not enough to
497 identify what failed, as shown below.
498
499 In complicated cases, we recommend using a *table-driven test* compared to the
500 helper macro variation, for example:
501
502 .. code-block:: c
503
504 int i;
505 char out[40];
506
507 struct sha1_test_case {
508 const char *str;
509 const char *sha1;
510 };
511
512 struct sha1_test_case cases[] = {
513 {
514 .str = "hello world",
515 .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
516 },
517 {
518 .str = "hello world!",
519 .sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
520 },
521 };
522 for (i = 0; i < ARRAY_SIZE(cases); ++i) {
523 sha1sum(cases[i].str, out);
524 KUNIT_EXPECT_STREQ_MSG(test, out, cases[i].sha1,
525 "sha1sum(%s)", cases[i].str);
526 }
527
528
529 There is more boilerplate code involved, but it can:
530
531 * be more readable when there are multiple inputs/outputs (due to field names).
532
533 * For example, see ``fs/ext4/inode-test.c``.
534
535 * reduce duplication if test cases are shared across multiple tests.
536
537 * For example: if we want to test ``sha256sum``, we could add a ``sha256``
538 field and reuse ``cases``.
539
540 * be converted to a "parameterized test".
541
542 Parameterized Testing
543 ~~~~~~~~~~~~~~~~~~~~~
544
545 To run a test case against multiple inputs, KUnit provides a parameterized
546 testing framework. This feature formalizes and extends the concept of
547 table-driven tests discussed previously.
548
549 A KUnit test is determined to be parameterized if a parameter generator function
550 is provided when registering the test case. A test user can either write their
551 own generator function or use one that is provided by KUnit. The generator
552 function is stored in ``kunit_case->generate_params`` and can be set using the
553 macros described in the section below.
554
555 To establish the terminology, a "parameterized test" is a test which is run
556 multiple times (once per "parameter" or "parameter run"). Each parameter run has
557 both its own independent ``struct kunit`` (the "parameter run context") and
558 access to a shared parent ``struct kunit`` (the "parameterized test context").
559
560 Passing Parameters to a Test
561 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
562 There are three ways to provide the parameters to a test:
563
564 Array Parameter Macros:
565
566 KUnit provides special support for the common table-driven testing pattern.
567 By applying either ``KUNIT_ARRAY_PARAM`` or ``KUNIT_ARRAY_PARAM_DESC`` to the
568 ``cases`` array from the previous section, we can create a parameterized test
569 as shown below:
570
571 .. code-block:: c
572
573 // This is copy-pasted from above.
574 struct sha1_test_case {
575 const char *str;
576 const char *sha1;
577 };
578 static const struct sha1_test_case cases[] = {
579 {
580 .str = "hello world",
581 .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
582 },
583 {
584 .str = "hello world!",
585 .sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
586 },
587 };
588
589 // Creates `sha1_gen_params()` to iterate over `cases` while using
590 // the struct member `str` for the case description.
591 KUNIT_ARRAY_PARAM_DESC(sha1, cases, str);
592
593 // Looks no different from a normal test.
594 static void sha1_test(struct kunit *test)
595 {
596 // This function can just contain the body of the for-loop.
597 // The former `cases[i]` is accessible under test->param_value.
598 char out[40];
599 struct sha1_test_case *test_param = (struct sha1_test_case *)(test->param_value);
600
601 sha1sum(test_param->str, out);
602 KUNIT_EXPECT_STREQ_MSG(test, out, test_param->sha1,
603 "sha1sum(%s)", test_param->str);
604 }
605
606 // Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the
607 // function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC.
608 static struct kunit_case sha1_test_cases[] = {
609 KUNIT_CASE_PARAM(sha1_test, sha1_gen_params),
610 {}
611 };
612
613 Custom Parameter Generator Function:
614
615 The generator function is responsible for generating parameters one-by-one
616 and has the following signature:
617 ``const void* (*)(struct kunit *test, const void *prev, char *desc)``.
618 You can pass the generator function to the ``KUNIT_CASE_PARAM``
619 or ``KUNIT_CASE_PARAM_WITH_INIT`` macros.
620
621 The function receives the previously generated parameter as the ``prev`` argument
622 (which is ``NULL`` on the first call) and can also access the parameterized
623 test context passed as the ``test`` argument. KUnit calls this function
624 repeatedly until it returns ``NULL``, which signifies that a parameterized
625 test ended.
626
627 Below is an example of how it works:
628
629 .. code-block:: c
630
631 #define MAX_TEST_BUFFER_SIZE 8
632
633 // Example generator function. It produces a sequence of buffer sizes that
634 // are powers of two, starting at 1 (e.g., 1, 2, 4, 8).
635 static const void *buffer_size_gen_params(struct kunit *test, const void *prev, char *desc)
636 {
637 long prev_buffer_size = (long)prev;
638 long next_buffer_size = 1; // Start with an initial size of 1.
639
640 // Stop generating parameters if the limit is reached or exceeded.
641 if (prev_buffer_size >= MAX_TEST_BUFFER_SIZE)
642 return NULL;
643
644 // For subsequent calls, calculate the next size by doubling the previous one.
645 if (prev)
646 next_buffer_size = prev_buffer_size << 1;
647
648 return (void *)next_buffer_size;
649 }
650
651 // Simple test to validate that kunit_kzalloc provides zeroed memory.
652 static void buffer_zero_test(struct kunit *test)
653 {
654 long buffer_size = (long)test->param_value;
655 // Use kunit_kzalloc to allocate a zero-initialized buffer. This makes the
656 // memory "parameter run managed," meaning it's automatically cleaned up at
657 // the end of each parameter run.
658 int *buf = kunit_kzalloc(test, buffer_size * sizeof(int), GFP_KERNEL);
659
660 // Ensure the allocation was successful.
661 KUNIT_ASSERT_NOT_NULL(test, buf);
662
663 // Loop through the buffer and confirm every element is zero.
664 for (int i = 0; i < buffer_size; i++)
665 KUNIT_EXPECT_EQ(test, buf[i], 0);
666 }
667
668 static struct kunit_case buffer_test_cases[] = {
669 KUNIT_CASE_PARAM(buffer_zero_test, buffer_size_gen_params),
670 {}
671 };
672
673 Runtime Parameter Array Registration in the Init Function:
674
675 For scenarios where you might need to initialize a parameterized test, you
676 can directly register a parameter array to the parameterized test context.
677
678 To do this, you must pass the parameterized test context, the array itself,
679 the array size, and a ``get_description()`` function to the
680 ``kunit_register_params_array()`` macro. This macro populates
681 ``struct kunit_params`` within the parameterized test context, effectively
682 storing a parameter array object. The ``get_description()`` function will
683 be used for populating parameter descriptions and has the following signature:
684 ``void (*)(struct kunit *test, const void *param, char *desc)``. Note that it
685 also has access to the parameterized test context.
686
687 .. important::
688 When using this way to register a parameter array, you will need to
689 manually pass ``kunit_array_gen_params()`` as the generator function to
690 ``KUNIT_CASE_PARAM_WITH_INIT``. ``kunit_array_gen_params()`` is a KUnit
691 helper that will use the registered array to generate the parameters.
692
693 If needed, instead of passing the KUnit helper, you can also pass your
694 own custom generator function that utilizes the parameter array. To
695 access the parameter array from within the parameter generator
696 function use ``test->params_array.params``.
697
698 The ``kunit_register_params_array()`` macro should be called within a
699 ``param_init()`` function that initializes the parameterized test and has
700 the following signature ``int (*)(struct kunit *test)``. For a detailed
701 explanation of this mechanism please refer to the "Adding Shared Resources"
702 section that is after this one. This method supports registering both
703 dynamically built and static parameter arrays.
704
705 The code snippet below shows the ``example_param_init_dynamic_arr`` test that
706 utilizes ``make_fibonacci_params()`` to create a dynamic array, which is then
707 registered using ``kunit_register_params_array()``. To see the full code
708 please refer to lib/kunit/kunit-example-test.c.
709
710 .. code-block:: c
711
712 /*
713 * Example of a parameterized test param_init() function that registers a dynamic
714 * array of parameters.
715 */
716 static int example_param_init_dynamic_arr(struct kunit *test)
717 {
718 size_t seq_size;
719 int *fibonacci_params;
720
721 kunit_info(test, "initializing parameterized test\n");
722
723 seq_size = 6;
724 fibonacci_params = make_fibonacci_params(test, seq_size);
725 if (!fibonacci_params)
726 return -ENOMEM;
727 /*
728 * Passes the dynamic parameter array information to the parameterized test
729 * context struct kunit. The array and its metadata will be stored in
730 * test->parent->params_array. The array itself will be located in
731 * params_data.params.
732 */
733 kunit_register_params_array(test, fibonacci_params, seq_size,
734 example_param_dynamic_arr_get_desc);
735 return 0;
736 }
737
738 static struct kunit_case example_test_cases[] = {
739 /*
740 * Note how we pass kunit_array_gen_params() to use the array we
741 * registered in example_param_init_dynamic_arr() to generate
742 * parameters.
743 */
744 KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr,
745 kunit_array_gen_params,
746 example_param_init_dynamic_arr,
747 example_param_exit_dynamic_arr),
748 {}
749 };
750
751 Adding Shared Resources
752 ^^^^^^^^^^^^^^^^^^^^^^^
753 All parameter runs in this framework hold a reference to the parameterized test
754 context, which can be accessed using the parent ``struct kunit`` pointer. The
755 parameterized test context is not used to execute any test logic itself; instead,
756 it serves as a container for shared resources.
757
758 It's possible to add resources to share between parameter runs within a
759 parameterized test by using ``KUNIT_CASE_PARAM_WITH_INIT``, to which you pass
760 custom ``param_init()`` and ``param_exit()`` functions. These functions run once
761 before and once after the parameterized test, respectively.
762
763 The ``param_init()`` function, with the signature ``int (*)(struct kunit *test)``,
764 can be used for adding resources to the ``resources`` or ``priv`` fields of
765 the parameterized test context, registering the parameter array, and any other
766 initialization logic.
767
768 The ``param_exit()`` function, with the signature ``void (*)(struct kunit *test)``,
769 can be used to release any resources that were not parameterized test managed (i.e.
770 not automatically cleaned up after the parameterized test ends) and for any other
771 exit logic.
772
773 Both ``param_init()`` and ``param_exit()`` are passed the parameterized test
774 context behind the scenes. However, the test case function receives the parameter
775 run context. Therefore, to manage and access shared resources from within a test
776 case function, you must use ``test->parent``.
777
778 For instance, finding a shared resource allocated by the Resource API requires
779 passing ``test->parent`` to ``kunit_find_resource()``. This principle extends to
780 all other APIs that might be used in the test case function, including
781 ``kunit_kzalloc()``, ``kunit_kmalloc_array()``, and others (see
782 Documentation/dev-tools/kunit/api/test.rst and the
783 Documentation/dev-tools/kunit/api/resource.rst).
784
785 .. note::
786 The ``suite->init()`` function, which executes before each parameter run,
787 receives the parameter run context. Therefore, any resources set up in
788 ``suite->init()`` are cleaned up after each parameter run.
789
790 The code below shows how you can add the shared resources. Note that this code
791 utilizes the Resource API, which you can read more about here:
792 Documentation/dev-tools/kunit/api/resource.rst. To see the full version of this
793 code please refer to lib/kunit/kunit-example-test.c.
794
795 .. code-block:: c
796
797 static int example_resource_init(struct kunit_resource *res, void *context)
798 {
799 ... /* Code that allocates memory and stores context in res->data. */
800 }
801
802 /* This function deallocates memory for the kunit_resource->data field. */
803 static void example_resource_free(struct kunit_resource *res)
804 {
805 kfree(res->data);
806 }
807
808 /* This match function locates a test resource based on defined criteria. */
809 static bool example_resource_alloc_match(struct kunit *test, struct kunit_resource *res,
810 void *match_data)
811 {
812 return res->data && res->free == example_resource_free;
813 }
814
815 /* Function to initialize the parameterized test. */
816 static int example_param_init(struct kunit *test)
817 {
818 int ctx = 3; /* Data to be stored. */
819 void *data = kunit_alloc_resource(test, example_resource_init,
820 example_resource_free,
821 GFP_KERNEL, &ctx);
822 if (!data)
823 return -ENOMEM;
824 kunit_register_params_array(test, example_params_array,
825 ARRAY_SIZE(example_params_array));
826 return 0;
827 }
828
829 /* Example test that uses shared resources in test->resources. */
830 static void example_params_test_with_init(struct kunit *test)
831 {
832 int threshold;
833 const struct example_param *param = test->param_value;
834 /* Here we pass test->parent to access the parameterized test context. */
835 struct kunit_resource *res = kunit_find_resource(test->parent,
836 example_resource_alloc_match,
837 NULL);
838
839 threshold = *((int *)res->data);
840 KUNIT_ASSERT_LE(test, param->value, threshold);
841 kunit_put_resource(res);
842 }
843
844 static struct kunit_case example_test_cases[] = {
845 KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params,
846 example_param_init, NULL),
847 {}
848 };
849
850 As an alternative to using the KUnit Resource API for sharing resources, you can
851 place them in ``test->parent->priv``. This serves as a more lightweight method
852 for resource storage, best for scenarios where complex resource management is
853 not required.
854
855 As stated previously ``param_init()`` and ``param_exit()`` get the parameterized
856 test context. So, you can directly use ``test->priv`` within ``param_init/exit``
857 to manage shared resources. However, from within the test case function, you must
858 navigate up to the parent ``struct kunit`` i.e. the parameterized test context.
859 Therefore, you need to use ``test->parent->priv`` to access those same
860 resources.
861
862 The resources placed in ``test->parent->priv`` will need to be allocated in
863 memory to persist across the parameter runs. If memory is allocated using the
864 KUnit memory allocation APIs (described more in the "Allocating Memory" section
865 below), you won't need to worry about deallocation. The APIs will make the memory
866 parameterized test 'managed', ensuring that it will automatically get cleaned up
867 after the parameterized test concludes.
868
869 The code below demonstrates example usage of the ``priv`` field for shared
870 resources:
871
872 .. code-block:: c
873
874 static const struct example_param {
875 int value;
876 } example_params_array[] = {
877 { .value = 3, },
878 { .value = 2, },
879 { .value = 1, },
880 { .value = 0, },
881 };
882
883 /* Initialize the parameterized test context. */
884 static int example_param_init_priv(struct kunit *test)
885 {
886 int ctx = 3; /* Data to be stored. */
887 int arr_size = ARRAY_SIZE(example_params_array);
888
889 /*
890 * Allocate memory using kunit_kzalloc(). Since the `param_init`
891 * function receives the parameterized test context, this memory
892 * allocation will be scoped to the lifetime of the parameterized test.
893 */
894 test->priv = kunit_kzalloc(test, sizeof(int), GFP_KERNEL);
895
896 /* Assign the context value to test->priv.*/
897 *((int *)test->priv) = ctx;
898
899 /* Register the parameter array. */
900 kunit_register_params_array(test, example_params_array, arr_size, NULL);
901 return 0;
902 }
903
904 static void example_params_test_with_init_priv(struct kunit *test)
905 {
906 int threshold;
907 const struct example_param *param = test->param_value;
908
909 /* By design, test->parent will not be NULL. */
910 KUNIT_ASSERT_NOT_NULL(test, test->parent);
911
912 /* Here we use test->parent->priv to access the shared resource. */
913 threshold = *(int *)test->parent->priv;
914
915 KUNIT_ASSERT_LE(test, param->value, threshold);
916 }
917
918 static struct kunit_case example_tests[] = {
919 KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_priv,
920 kunit_array_gen_params,
921 example_param_init_priv, NULL),
922 {}
923 };
924
925 Allocating Memory
926 -----------------
927
928 Where you might use ``kzalloc``, you can instead use ``kunit_kzalloc`` as KUnit
929 will then ensure that the memory is freed once the test completes.
930
931 This is useful because it lets us use the ``KUNIT_ASSERT_EQ`` macros to exit
932 early from a test without having to worry about remembering to call ``kfree``.
933 For example:
934
935 .. code-block:: c
936
937 void example_test_allocation(struct kunit *test)
938 {
939 char *buffer = kunit_kzalloc(test, 16, GFP_KERNEL);
940 /* Ensure allocation succeeded. */
941 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
942
943 KUNIT_ASSERT_STREQ(test, buffer, "");
944 }
945
946 Registering Cleanup Actions
947 ---------------------------
948
949 If you need to perform some cleanup beyond simple use of ``kunit_kzalloc``,
950 you can register a custom "deferred action", which is a cleanup function
951 run when the test exits (whether cleanly, or via a failed assertion).
952
953 Actions are simple functions with no return value, and a single ``void*``
954 context argument, and fulfill the same role as "cleanup" functions in Python
955 and Go tests, "defer" statements in languages which support them, and
956 (in some cases) destructors in RAII languages.
957
958 These are very useful for unregistering things from global lists, closing
959 files or other resources, or freeing resources.
960
961 For example:
962
963 .. code-block:: C
964
965 static void cleanup_device(void *ctx)
966 {
967 struct device *dev = (struct device *)ctx;
968
969 device_unregister(dev);
970 }
971
972 void example_device_test(struct kunit *test)
973 {
974 struct my_device dev;
975
976 device_register(&dev);
977
978 kunit_add_action(test, &cleanup_device, &dev);
979 }
980
981 Note that, for functions like device_unregister which only accept a single
982 pointer-sized argument, it's possible to automatically generate a wrapper
983 with the ``KUNIT_DEFINE_ACTION_WRAPPER()`` macro, for example:
984
985 .. code-block:: C
986
987 KUNIT_DEFINE_ACTION_WRAPPER(device_unregister, device_unregister_wrapper, struct device *);
988 kunit_add_action(test, &device_unregister_wrapper, &dev);
989
990 You should do this in preference to manually casting to the ``kunit_action_t`` type,
991 as casting function pointers will break Control Flow Integrity (CFI).
992
993 ``kunit_add_action`` can fail if, for example, the system is out of memory.
994 You can use ``kunit_add_action_or_reset`` instead which runs the action
995 immediately if it cannot be deferred.
996
997 If you need more control over when the cleanup function is called, you
998 can trigger it early using ``kunit_release_action``, or cancel it entirely
999 with ``kunit_remove_action``.
1002 Testing Static Functions
1003 ------------------------
1005 If you want to test static functions without exposing those functions outside of
1006 testing, one option is conditionally export the symbol. When KUnit is enabled,
1007 the symbol is exposed but remains static otherwise. To use this method, follow
1008 the template below.
1010 .. code-block:: c
1012 /* In the file containing functions to test "my_file.c" */
1014 #include <kunit/visibility.h>
1015 #include <my_file.h>
1016 ...
1017 VISIBLE_IF_KUNIT int do_interesting_thing()
1018 {
1019 ...
1020 }
1021 EXPORT_SYMBOL_IF_KUNIT(do_interesting_thing);
1023 /* In the header file "my_file.h" */
1025 #if IS_ENABLED(CONFIG_KUNIT)
1026 int do_interesting_thing(void);
1027 #endif
1029 /* In the KUnit test file "my_file_test.c" */
1031 #include <kunit/visibility.h>
1032 #include <my_file.h>
1033 ...
1034 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
1035 ...
1036 // Use do_interesting_thing() in tests
1038 For a full example, see this `patch <https://lore.kernel.org/all/[email protected]/>`_
1039 where a test is modified to conditionally expose static functions for testing
1040 using the macros above.
1042 As an **alternative** to the method above, you could conditionally ``#include``
1043 the test file at the end of your .c file. This is not recommended but works
1044 if needed. For example:
1046 .. code-block:: c
1048 /* In "my_file.c" */
1050 static int do_interesting_thing();
1052 #ifdef CONFIG_MY_KUNIT_TEST
1053 #include "my_kunit_test.c"
1054 #endif
1056 Injecting Test-Only Code
1057 ------------------------
1059 Similar to as shown above, we can add test-specific logic. For example:
1061 .. code-block:: c
1063 /* In my_file.h */
1065 #ifdef CONFIG_MY_KUNIT_TEST
1066 /* Defined in my_kunit_test.c */
1067 void test_only_hook(void);
1068 #else
1069 void test_only_hook(void) { }
1070 #endif
1072 This test-only code can be made more useful by accessing the current ``kunit_test``
1073 as shown in next section: *Accessing The Current Test*.
1075 Accessing The Current Test
1076 --------------------------
1078 In some cases, we need to call test-only code from outside the test file. This
1079 is helpful, for example, when providing a fake implementation of a function, or
1080 to fail any current test from within an error handler.
1081 We can do this via the ``kunit_test`` field in ``task_struct``, which we can
1082 access using the ``kunit_get_current_test()`` function in ``kunit/test-bug.h``.
1084 ``kunit_get_current_test()`` is safe to call even if KUnit is not enabled. If
1085 KUnit is not enabled, or if no test is running in the current task, it will
1086 return ``NULL``. This compiles down to either a no-op or a static key check,
1087 so will have a negligible performance impact when no test is running.
1089 The example below uses this to implement a "mock" implementation of a function, ``foo``:
1091 .. code-block:: c
1093 #include <kunit/test-bug.h> /* for kunit_get_current_test */
1095 struct test_data {
1096 int foo_result;
1097 int want_foo_called_with;
1098 };
1100 static int fake_foo(int arg)
1101 {
1102 struct kunit *test = kunit_get_current_test();
1103 struct test_data *test_data = test->priv;
1105 KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
1106 return test_data->foo_result;
1107 }
1109 static void example_simple_test(struct kunit *test)
1110 {
1111 /* Assume priv (private, a member used to pass test data from
1112 * the init function) is allocated in the suite's .init */
1113 struct test_data *test_data = test->priv;
1115 test_data->foo_result = 42;
1116 test_data->want_foo_called_with = 1;
1118 /* In a real test, we'd probably pass a pointer to fake_foo somewhere
1119 * like an ops struct, etc. instead of calling it directly. */
1120 KUNIT_EXPECT_EQ(test, fake_foo(1), 42);
1121 }
1123 In this example, we are using the ``priv`` member of ``struct kunit`` as a way
1124 of passing data to the test from the init function. In general ``priv`` is
1125 pointer that can be used for any user data. This is preferred over static
1126 variables, as it avoids concurrency issues.
1128 Had we wanted something more flexible, we could have used a named ``kunit_resource``.
1129 Each test can have multiple resources which have string names providing the same
1130 flexibility as a ``priv`` member, but also, for example, allowing helper
1131 functions to create resources without conflicting with each other. It is also
1132 possible to define a clean up function for each resource, making it easy to
1133 avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/resource.rst.
1135 Failing The Current Test
1136 ------------------------
1138 If we want to fail the current test, we can use ``kunit_fail_current_test(fmt, args...)``
1139 which is defined in ``<kunit/test-bug.h>`` and does not require pulling in ``<kunit/test.h>``.
1140 For example, we have an option to enable some extra debug checks on some data
1141 structures as shown below:
1143 .. code-block:: c
1145 #include <kunit/test-bug.h>
1147 #ifdef CONFIG_EXTRA_DEBUG_CHECKS
1148 static void validate_my_data(struct data *data)
1149 {
1150 if (is_valid(data))
1151 return;
1153 kunit_fail_current_test("data %p is invalid", data);
1155 /* Normal, non-KUnit, error reporting code here. */
1156 }
1157 #else
1158 static void my_debug_function(void) { }
1159 #endif
1161 ``kunit_fail_current_test()`` is safe to call even if KUnit is not enabled. If
1162 KUnit is not enabled, or if no test is running in the current task, it will do
1163 nothing. This compiles down to either a no-op or a static key check, so will
1164 have a negligible performance impact when no test is running.
1166 Managing Fake Devices and Drivers
1167 ---------------------------------
1169 When testing drivers or code which interacts with drivers, many functions will
1170 require a ``struct device`` or ``struct device_driver``. In many cases, setting
1171 up a real device is not required to test any given function, so a fake device
1172 can be used instead.
1174 KUnit provides helper functions to create and manage these fake devices, which
1175 are internally of type ``struct kunit_device``, and are attached to a special
1176 ``kunit_bus``. These devices support managed device resources (devres), as
1177 described in Documentation/driver-api/driver-model/devres.rst
1179 To create a KUnit-managed ``struct device_driver``, use ``kunit_driver_create()``,
1180 which will create a driver with the given name, on the ``kunit_bus``. This driver
1181 will automatically be destroyed when the corresponding test finishes, but can also
1182 be manually destroyed with ``driver_unregister()``.
1184 To create a fake device, use the ``kunit_device_register()``, which will create
1185 and register a device, using a new KUnit-managed driver created with ``kunit_driver_create()``.
1186 To provide a specific, non-KUnit-managed driver, use ``kunit_device_register_with_driver()``
1187 instead. Like with managed drivers, KUnit-managed fake devices are automatically
1188 cleaned up when the test finishes, but can be manually cleaned up early with
1189 ``kunit_device_unregister()``.
1191 The KUnit devices should be used in preference to ``root_device_register()``, and
1192 instead of ``platform_device_register()`` in cases where the device is not otherwise
1193 a platform device.
1195 For example:
1197 .. code-block:: c
1199 #include <kunit/device.h>
1201 static void test_my_device(struct kunit *test)
1202 {
1203 struct device *fake_device;
1204 const char *dev_managed_string;
1206 // Create a fake device.
1207 fake_device = kunit_device_register(test, "my_device");
1208 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_device)
1210 // Pass it to functions which need a device.
1211 dev_managed_string = devm_kstrdup(fake_device, "Hello, World!");
1213 // Everything is cleaned up automatically when the test ends.
1214 }

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Test case, expectation과 assertion

1-129

SPDX 라이선스 식별자: GPL-2.0

테스트 작성

Test case

KUnit의 기본 단위는 test case입니다. Test case는 `void (*)(struct kunit *test)` signature를 가진 function입니다. 검사할 function을 호출한 뒤 어떤 일이 일어나야 하는지 expectation을 설정합니다.

void example_test_success(struct kunit *test)
{
}

void example_test_failure(struct kunit *test)
{
        KUNIT_FAIL(test, "This test never passes.");
}

위 예에서 `example_test_success`는 아무 일도 하지 않아 항상 통과합니다. 설정된 expectation이 없으므로 모든 expectation이 통과한 것으로 처리됩니다. 반면 `example_test_failure`는 message를 기록하고 test case를 실패시키는 특수 expectation인 `KUNIT_FAIL`을 호출하므로 항상 실패합니다.

Expectation

Expectation은 test에서 특정 code가 어떤 동작을 해야 한다고 기대하는 조건입니다. Function처럼 호출하며, 검사 대상 code의 behavior에 관한 expectation들을 설정해 test를 만듭니다. 하나 이상의 expectation이 실패하면 test case가 실패하고 failure 정보가 log에 기록됩니다.

void add_test_basic(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, 1, add(1, 0));
        KUNIT_EXPECT_EQ(test, 2, add(1, 1));
}

`add_test_basic`은 `add` function의 behavior를 여러 번 확인합니다. 첫 parameter는 항상 현재 test context 정보를 담은 `struct kunit *`입니다. 두 번째 parameter는 expected value이고 마지막 parameter는 actual value입니다.

`add`가 모든 expectation을 만족하면 `add_test_basic`이 통과하고 하나라도 만족하지 못하면 test case가 실패합니다.

Expectation 하나가 위반되면 test case는 실패 상태가 되지만 실행은 계속되어 test case가 끝나거나 다른 방식으로 종료될 때까지 나머지 expectation도 시도합니다. 뒤에서 설명할 assertion과 다른 점입니다.

더 많은 KUnit expectation은 `Documentation/dev-tools/kunit/api/test.rst`를 참조하십시오.

참고: 하나의 test case는 짧고 이해하기 쉬우며 하나의 behavior에 집중해야 합니다.

앞의 `add` function을 엄밀하게 검사하려면 기본 덧셈, 음수, 최대값과 overflow처럼 각 property를 별도 test case로 작성합니다.

void add_test_basic(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, 1, add(1, 0));
        KUNIT_EXPECT_EQ(test, 2, add(1, 1));
}

void add_test_negative(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, 0, add(-1, 1));
}

void add_test_max(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX));
        KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN));
}

void add_test_overflow(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, INT_MIN, add(INT_MAX, 1));
}

Assertion

Assertion은 expectation과 비슷하지만 조건을 만족하지 않으면 test case를 즉시 종료합니다.

static void test_sort(struct kunit *test)
{
        int *a, i, r = 1;
        a = kunit_kmalloc_array(test, TEST_LEN, sizeof(*a), GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, a);
        for (i = 0; i < TEST_LEN; i++) {
                r = (r * 725861) % 6599;
                a[i] = r;
        }
        sort(a, TEST_LEN, sizeof(*a), cmpint, NULL);
        for (i = 0; i < TEST_LEN-1; i++)
                KUNIT_EXPECT_LE(test, a[i], a[i + 1]);
}

이 예에서는 `sort()`를 검사할 array가 반드시 필요합니다. 따라서 allocation error가 나면 `KUNIT_ASSERT_NOT_ERR_OR_NULL()`로 test를 중단합니다. Allocation에 성공한 뒤 정렬 결과의 인접 element가 순서대로인지 expectation으로 모두 확인합니다.

참고: 다른 test framework의 `ASSERT` macro는 흔히 `return`을 호출해 test function 안에서만 동작합니다. KUnit은 failure 시 현재 kthread를 중지하므로 어느 위치에서든 assertion을 호출할 수 있습니다.

경고: 예외가 있습니다. Suite의 `exit()` function이나 resource의 free function에서는 assertion을 사용하면 안 됩니다. 이 function들은 test shutdown 중 실행되므로 assertion이 이후 cleanup code 실행을 막아 memory leak을 일으킬 수 있습니다.

Expectation과 assertion 비교
종류실패 시 동작주요 용도
KUNIT_EXPECTCase는 실패하지만 다음 검사를 계속 실행여러 독립 결과 수집
KUNIT_ASSERT현재 test case를 즉시 종료후속 검사의 전제조건 확인
KUNIT_FAILMessage를 기록하고 case 실패직접 정의한 실패 조건

Failure 뒤 실행 흐름과 적합한 용도를 구분했습니다.

Error message와 test suite lifecycle

130-215

Error message customizing

각 `KUNIT_EXPECT`와 `KUNIT_ASSERT` macro에는 `_MSG` variant가 있습니다. Format string과 argument를 받아 자동 생성되는 error message에 추가 context를 제공합니다.

char some_str[41];
generate_sha1_hex_string(some_str);

/* Before. Not easy to tell why the test failed. */
KUNIT_EXPECT_EQ(test, strlen(some_str), 40);

/* After. Now we see the offending string. */
KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);

또는 `KUNIT_FAIL()`을 사용해 error message 전체를 직접 제어할 수 있습니다.

/* Before */
KUNIT_EXPECT_EQ(test, some_setup_function(), 0);

/* After: full control over the failure message. */
if (some_setup_function())
        KUNIT_FAIL(test, "Failed to setup thing for testing");

Test suite

Unit의 모든 behavior를 다루려면 많은 test case가 필요하며 비슷한 테스트가 반복되기 쉽습니다. KUnit을 포함한 대부분의 unit testing framework는 중복을 줄이기 위해 test suite를 제공합니다.

Test suite는 하나의 code unit을 검사하는 test case 모음이며, 전체 suite 또는 각 test case 앞뒤에 실행되는 선택적 setup과 teardown function을 포함할 수 있습니다.

참고: Test case는 test suite와 연결되어 있어야만 실행됩니다.

static struct kunit_case example_test_cases[] = {
        KUNIT_CASE(example_test_foo),
        KUNIT_CASE(example_test_bar),
        KUNIT_CASE(example_test_baz),
        {}
};

static struct kunit_suite example_test_suite = {
        .name = "example",
        .init = example_test_init,
        .exit = example_test_exit,
        .suite_init = example_suite_init,
        .suite_exit = example_suite_exit,
        .test_cases = example_test_cases,
};
kunit_test_suite(example_test_suite);

이 예에서 `example_test_suite`는 먼저 `example_suite_init`을 실행하고 `example_test_foo`, `example_test_bar`, `example_test_baz`를 차례로 실행합니다. 각 case 직전에는 `example_test_init`, 직후에는 `example_test_exit`가 호출됩니다. 모든 작업 뒤에는 `example_suite_exit`가 호출됩니다.

`kunit_test_suite(example_test_suite)`는 suite를 KUnit test framework에 등록합니다.

참고: `init` 또는 `suite_init`이 실패해도 `exit`와 `suite_exit`는 실행됩니다. Init function이 error를 만나거나 일찍 종료해 일관되지 않은 state가 생긴 경우도 처리할 수 있게 작성해야 합니다.

`kunit_test_suite(...)` macro는 지정 suite를 special linker section에 넣도록 linker에 지시합니다. KUnit은 `late_init` 뒤 또는 test가 module로 build된 경우 module load 시 suite를 실행합니다.

자세한 내용은 `Documentation/dev-tools/kunit/api/test.rst`를 참조하십시오.

KUnit suite lifecycle
suite_init전체 suite 시작 전 한 번
init각 test case 직전
test caseExpectation과 assertion 실행
exit각 test case 직후, init 실패 시에도 실행
suite_exit전체 suite 종료 뒤, suite_init 실패 시에도 실행

Suite 단위와 case 단위 callback의 호출 순서를 나타냅니다.

다른 architecture용 테스트

216-243

원문의 `kunit-on-non-uml` anchor는 이 절을 가리킵니다.

다른 architecture용 테스트 작성

특정 architecture에서만 실행되는 테스트보다 UML에서 실행되는 테스트가 좋습니다. 특정 hardware에서만 실행되는 테스트보다 QEMU처럼 쉽게 무료로 구할 수 있는 software environment에서 실행되는 테스트가 좋습니다.

그럼에도 architecture 또는 hardware에 특화된 테스트가 필요한 타당한 이유가 있습니다. 예를 들어 실제로 `arch/some-arch/*`에 속하는 code를 검사해야 할 수 있습니다.

이 경우에도 physical hardware dependency를 최소화하십시오. 일부 test case는 hardware가 필요하지 않고 실제 hardware가 꼭 필요한 case는 소수일 수 있습니다. Hardware가 없을 때 test를 비활성화하지 말고 skip할 수 있습니다.

Hardware-specific 부분을 정확히 좁힌 뒤에는 일반 KUnit test와 같은 절차로 작성하고 실행합니다.

중요: Hardware state를 reset해야 할 수 있습니다. Reset이 불가능하면 invocation 한 번에 test case 하나만 실행할 수 있습니다.

TODO: Architecture-dependent KUnit test의 실제 예제를 추가해야 합니다.

Behavior 격리와 kernel class

244-312

일반 pattern

Behavior 격리

Unit testing은 검사할 code 양을 하나의 unit으로 제한하고, 그 unit이 function을 호출할 때 어떤 code가 실행되는지 제어합니다. API 일부로 노출된 function은 나머지 code base에 영향을 주지 않고 definition을 바꿀 수 있어야 합니다.

Kernel에서는 구현자가 제공한 function pointer를 struct에 담는 class와 compile time에 definition을 선택하는 architecture-specific function이라는 두 construct가 이 역할을 합니다.

Class

Class는 C language에 내장된 construct는 아니지만 쉽게 유도할 수 있는 개념입니다. GNOME GObject 같은 표준 object-oriented library를 사용하지 않는 project마다 조금씩 다른 object-oriented programming 방식을 가지며 Linux kernel도 예외가 아닙니다.

Kernel object-oriented programming의 중심은 class입니다. Kernel에서 class는 function pointer를 포함한 struct입니다. Implementer와 user가 function을 직접 호출하지 않으면서 동일한 function signature를 사용하도록 강제해 양쪽 사이의 contract를 만듭니다.

Class의 function pointer는 class handle이라 부르는 class pointer를 parameter 중 하나로 받아야 합니다. 따라서 method는 field에 접근할 수 있고 같은 implementation이 여러 instance를 가질 수 있습니다.

Child class가 parent class를 자신의 struct 안에 embedding하면 parent class를 override할 수 있습니다. Child method가 호출될 때 전달된 pointer는 child 안의 parent를 가리킵니다. Parent가 child struct 안에서 항상 고정 offset에 있으므로 child implementation은 자신을 가리키는 pointer를 계산할 수 있습니다.

struct shape {
        int (*area)(struct shape *this);
};

struct rectangle {
        struct shape parent;
        int length;
        int width;
};

int rectangle_area(struct shape *this)
{
        struct rectangle *self = container_of(this, struct rectangle, parent);

        return self->length * self->width;
};

void rectangle_new(struct rectangle *self, int length, int width)
{
        self->parent.area = rectangle_area;
        self->length = length;
        self->width = width;
}

이 예에서는 `container_of`가 parent `shape` pointer로부터 child `rectangle` pointer를 계산합니다.

Class fake와 EEPROM buffer 테스트

313-472

Class faking

Class method를 호출하는 code를 unit test하려면 method behavior를 제어할 수 있어야 합니다. 제어할 수 없다면 unit test가 아니라 integration test가 됩니다.

Fake class는 production instance와 다른 code를 구현하지만 caller 관점에서는 동일하게 동작합니다. 다루기 어렵거나 느린 dependency를 대체할 때 사용합니다. 예를 들어 EEPROM content를 internal buffer에 저장하는 fake EEPROM을 만들 수 있습니다.

다음은 EEPROM을 나타내는 class입니다.

struct eeprom {
        ssize_t (*read)(struct eeprom *this, size_t offset, char *buffer, size_t count);
        ssize_t (*write)(struct eeprom *this, size_t offset, const char *buffer, size_t count);
};

검사할 대상은 EEPROM write를 buffering하는 code입니다.

struct eeprom_buffer {
        ssize_t (*write)(struct eeprom_buffer *this, const char *buffer, size_t count);
        int flush(struct eeprom_buffer *this);
        size_t flush_count; /* Flushes when buffer exceeds flush_count. */
};

struct eeprom_buffer *new_eeprom_buffer(struct eeprom *eeprom);
void destroy_eeprom_buffer(struct eeprom *eeprom);

Underlying EEPROM은 다음 fake implementation으로 대체합니다.

struct fake_eeprom {
        struct eeprom parent;
        char contents[FAKE_EEPROM_CONTENTS_SIZE];
};

ssize_t fake_eeprom_read(struct eeprom *parent, size_t offset, char *buffer, size_t count)
{
        struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);

        count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset);
        memcpy(buffer, this->contents + offset, count);

        return count;
}

ssize_t fake_eeprom_write(struct eeprom *parent, size_t offset, const char *buffer, size_t count)
{
        struct fake_eeprom *this = container_of(parent, struct fake_eeprom, parent);

        count = min(count, FAKE_EEPROM_CONTENTS_SIZE - offset);
        memcpy(this->contents + offset, buffer, count);

        return count;
}

void fake_eeprom_init(struct fake_eeprom *this)
{
        this->parent.read = fake_eeprom_read;
        this->parent.write = fake_eeprom_write;
        memset(this->contents, 0, FAKE_EEPROM_CONTENTS_SIZE);
}

`fake_eeprom`은 실제 device 대신 memory의 `contents` array를 사용하고 parent class의 `read`와 `write` method를 fake function으로 연결합니다.

이제 이를 사용해 `struct eeprom_buffer`를 검사합니다.

struct eeprom_buffer_test {
        struct fake_eeprom *fake_eeprom;
        struct eeprom_buffer *eeprom_buffer;
};

static void eeprom_buffer_test_does_not_write_until_flush(struct kunit *test)
{
        struct eeprom_buffer_test *ctx = test->priv;
        struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
        struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
        char buffer[] = {0xff};

        eeprom_buffer->flush_count = SIZE_MAX;

        eeprom_buffer->write(eeprom_buffer, buffer, 1);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);

        eeprom_buffer->write(eeprom_buffer, buffer, 1);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0);

        eeprom_buffer->flush(eeprom_buffer);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
}

static void eeprom_buffer_test_flushes_after_flush_count_met(struct kunit *test)
{
        struct eeprom_buffer_test *ctx = test->priv;
        struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
        struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
        char buffer[] = {0xff};

        eeprom_buffer->flush_count = 2;

        eeprom_buffer->write(eeprom_buffer, buffer, 1);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);

        eeprom_buffer->write(eeprom_buffer, buffer, 1);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
}

static void eeprom_buffer_test_flushes_increments_of_flush_count(struct kunit *test)
{
        struct eeprom_buffer_test *ctx = test->priv;
        struct eeprom_buffer *eeprom_buffer = ctx->eeprom_buffer;
        struct fake_eeprom *fake_eeprom = ctx->fake_eeprom;
        char buffer[] = {0xff, 0xff};

        eeprom_buffer->flush_count = 2;

        eeprom_buffer->write(eeprom_buffer, buffer, 1);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0);

        eeprom_buffer->write(eeprom_buffer, buffer, 2);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[0], 0xff);
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[1], 0xff);
        /* Should have only flushed the first two bytes. */
        KUNIT_EXPECT_EQ(test, fake_eeprom->contents[2], 0);
}

static int eeprom_buffer_test_init(struct kunit *test)
{
        struct eeprom_buffer_test *ctx;

        ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);

        ctx->fake_eeprom = kunit_kzalloc(test, sizeof(*ctx->fake_eeprom), GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->fake_eeprom);
        fake_eeprom_init(ctx->fake_eeprom);

        ctx->eeprom_buffer = new_eeprom_buffer(&ctx->fake_eeprom->parent);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->eeprom_buffer);

        test->priv = ctx;

        return 0;
}

static void eeprom_buffer_test_exit(struct kunit *test)
{
        struct eeprom_buffer_test *ctx = test->priv;

        destroy_eeprom_buffer(ctx->eeprom_buffer);
}

첫 case는 `flush_count=SIZE_MAX`에서 두 번 write해도 fake storage가 변하지 않다가 명시적 flush 뒤 두 byte가 `0xff`가 되는지 확인합니다.

두 번째 case는 `flush_count=2`에 도달하면 두 byte가 자동 flush되는지 확인합니다. 세 번째 case는 세 byte가 buffered되어도 threshold의 배수인 앞 두 byte만 flush되는지 확인합니다.

Suite init은 `kunit_kzalloc`으로 context와 fake EEPROM을 할당하고 fake를 초기화한 뒤 `new_eeprom_buffer`에 parent interface를 주입해 `test->priv`에 저장합니다. Exit은 생성한 EEPROM buffer를 destroy합니다.

Fake EEPROM dependency 주입
eeprom_buffer`struct eeprom` interface에만 의존
fake_eepromParent interface와 in-memory contents 제공
write 호출Threshold 전에는 fake contents 유지
flush 또는 thresholdBuffered byte를 fake contents로 반영
Expectation각 offset의 byte 값 확인

Production dependency를 memory-backed fake로 바꾸어 buffer behavior만 격리하는 구조입니다.

여러 input과 table-driven test

473-541

여러 input에 대한 테스트

Hash function처럼 input 공간이 넓은 code는 몇 개 input만 검사해서 올바른 동작을 보장할 수 없습니다.

각 input마다 호출할 helper macro 또는 function을 작성할 수 있습니다. `sha1sum(1)`을 검사하는 예는 다음과 같습니다.

#define TEST_SHA1(in, want) \
        sha1sum(in, out); \
        KUNIT_EXPECT_STREQ_MSG(test, out, want, "sha1sum(%s)", in);

char out[40];
TEST_SHA1("hello world",  "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
TEST_SHA1("hello world!", "430ce34d020724ed75a196dfc2ad67c77772d169");

`KUNIT_EXPECT_STREQ`의 `_MSG` variant를 사용해 더 자세한 error를 출력하고 helper macro 안의 assertion 의미를 분명히 합니다.

Loop 또는 helper function에서 같은 expectation을 여러 번 호출하면 source line number만으로 어느 input이 실패했는지 알기 어렵습니다. 이런 경우 `_MSG` variant가 유용합니다.

복잡한 경우에는 helper macro보다 table-driven test를 권장합니다.

int i;
char out[40];

struct sha1_test_case {
        const char *str;
        const char *sha1;
};

struct sha1_test_case cases[] = {
        {
                .str = "hello world",
                .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
        },
        {
                .str = "hello world!",
                .sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
        },
};
for (i = 0; i < ARRAY_SIZE(cases); ++i) {
        sha1sum(cases[i].str, out);
        KUNIT_EXPECT_STREQ_MSG(test, out, cases[i].sha1,
                              "sha1sum(%s)", cases[i].str);
}

Boilerplate는 늘지만 field name 덕분에 input과 output이 여러 개일 때 읽기 쉽습니다. 예는 `fs/ext4/inode-test.c`를 참조하십시오.

여러 test가 test case data를 공유하면 duplication을 줄일 수 있습니다. 예를 들어 `sha256sum`을 검사하려면 `sha256` field를 추가하고 같은 `cases`를 재사용할 수 있습니다.

또한 table을 parameterized test로 변환할 수 있습니다.

Parameterized test와 parameter 제공 방식

542-750

Parameterized testing

KUnit은 하나의 test case를 여러 input에 실행하는 parameterized testing framework를 제공합니다. 앞서 설명한 table-driven test 개념을 정형화하고 확장합니다.

Test case를 등록할 때 parameter generator function을 제공하면 KUnit은 이를 parameterized test로 판단합니다. 사용자는 generator를 직접 작성하거나 KUnit 제공 generator를 사용할 수 있습니다. Generator는 `kunit_case->generate_params`에 저장되며 아래 macro로 설정합니다.

Parameterized test는 parameter 또는 parameter run마다 한 번씩 여러 번 실행됩니다. 각 parameter run은 독립적인 `struct kunit`, 즉 parameter run context를 가지며 동시에 공유 parent `struct kunit`, 즉 parameterized test context에 접근할 수 있습니다.

Test에 parameter 전달

Parameter를 제공하는 방법은 세 가지입니다.

Array parameter macro

KUnit은 일반적인 table-driven pattern을 특별 지원합니다. 앞 절의 `cases` array에 `KUNIT_ARRAY_PARAM` 또는 `KUNIT_ARRAY_PARAM_DESC`를 적용해 parameterized test를 만들 수 있습니다.

// This is copy-pasted from above.
struct sha1_test_case {
        const char *str;
        const char *sha1;
};
static const struct sha1_test_case cases[] = {
        {
                .str = "hello world",
                .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
        },
        {
                .str = "hello world!",
                .sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
        },
};

// Creates `sha1_gen_params()` to iterate over `cases` while using
// the struct member `str` for the case description.
KUNIT_ARRAY_PARAM_DESC(sha1, cases, str);

// Looks no different from a normal test.
static void sha1_test(struct kunit *test)
{
        // This function can just contain the body of the for-loop.
        // The former `cases[i]` is accessible under test->param_value.
        char out[40];
        struct sha1_test_case *test_param = (struct sha1_test_case *)(test->param_value);

        sha1sum(test_param->str, out);
        KUNIT_EXPECT_STREQ_MSG(test, out, test_param->sha1,
                              "sha1sum(%s)", test_param->str);
}

// Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the
// function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC.
static struct kunit_case sha1_test_cases[] = {
        KUNIT_CASE_PARAM(sha1_test, sha1_gen_params),
        {}
};

`KUNIT_ARRAY_PARAM_DESC`는 array를 순회하는 `sha1_gen_params()`를 만들고 `str` member를 case description으로 사용합니다. Test body는 `test->param_value`에서 현재 element를 얻습니다. 등록에는 `KUNIT_CASE` 대신 `KUNIT_CASE_PARAM`과 생성된 generator를 사용합니다.

Custom parameter generator function

Generator는 parameter를 하나씩 생성하며 signature는 `const void* (*)(struct kunit *test, const void *prev, char *desc)`입니다. `KUNIT_CASE_PARAM` 또는 `KUNIT_CASE_PARAM_WITH_INIT`에 전달할 수 있습니다.

Function은 이전에 생성한 parameter를 `prev`로 받으며 첫 호출에서는 NULL입니다. `test` argument로 parameterized test context에도 접근할 수 있습니다. KUnit은 generator가 NULL을 반환해 parameterized test 종료를 알릴 때까지 반복 호출합니다.

#define MAX_TEST_BUFFER_SIZE 8

// Example generator function. It produces a sequence of buffer sizes that
// are powers of two, starting at 1 (e.g., 1, 2, 4, 8).
static const void *buffer_size_gen_params(struct kunit *test, const void *prev, char *desc)
{
        long prev_buffer_size = (long)prev;
        long next_buffer_size = 1; // Start with an initial size of 1.

        // Stop generating parameters if the limit is reached or exceeded.
        if (prev_buffer_size >= MAX_TEST_BUFFER_SIZE)
                return NULL;

        // For subsequent calls, calculate the next size by doubling the previous one.
        if (prev)
                next_buffer_size = prev_buffer_size << 1;

        return (void *)next_buffer_size;
}

// Simple test to validate that kunit_kzalloc provides zeroed memory.
static void buffer_zero_test(struct kunit *test)
{
        long buffer_size = (long)test->param_value;
        // Use kunit_kzalloc to allocate a zero-initialized buffer. This makes the
        // memory "parameter run managed," meaning it's automatically cleaned up at
        // the end of each parameter run.
        int *buf = kunit_kzalloc(test, buffer_size * sizeof(int), GFP_KERNEL);

        // Ensure the allocation was successful.
        KUNIT_ASSERT_NOT_NULL(test, buf);

        // Loop through the buffer and confirm every element is zero.
        for (int i = 0; i < buffer_size; i++)
                KUNIT_EXPECT_EQ(test, buf[i], 0);
}

static struct kunit_case buffer_test_cases[] = {
        KUNIT_CASE_PARAM(buffer_zero_test, buffer_size_gen_params),
        {}
};

예제 generator는 1부터 시작해 2배씩 늘어난 1, 2, 4, 8 buffer size를 생성하고 limit에 도달하면 NULL을 반환합니다. 각 run은 해당 크기의 zero-initialized memory를 할당하고 모든 element가 0인지 확인합니다.

Init function에서 runtime parameter array 등록

Parameterized test 초기화가 필요한 경우 parameterized test context에 array를 직접 등록할 수 있습니다. `kunit_register_params_array()`에 context, array, size와 `get_description()` function을 전달합니다.

이 macro는 parameterized test context의 `struct kunit_params`를 채워 parameter array object를 저장합니다. Description function signature는 `void (*)(struct kunit *test, const void *param, char *desc)`이며 parameterized test context에 접근할 수 있습니다.

중요: 이 방식으로 array를 등록할 때는 `KUNIT_CASE_PARAM_WITH_INIT`의 generator로 `kunit_array_gen_params()`를 직접 전달해야 합니다. 이 KUnit helper가 등록된 array에서 parameter를 생성합니다.

필요하다면 helper 대신 parameter array를 사용하는 custom generator를 전달할 수 있습니다. Generator 안에서는 `test->params_array.params`로 array에 접근합니다.

`kunit_register_params_array()`는 parameterized test를 초기화하는 `param_init()` 안에서 호출해야 합니다. Signature는 `int (*)(struct kunit *test)`입니다. 다음 절의 shared resource mechanism과 연결되며 dynamic array와 static array 모두 등록할 수 있습니다.

다음 `example_param_init_dynamic_arr`는 `make_fibonacci_params()`로 dynamic array를 만들고 등록합니다. 전체 code는 `lib/kunit/kunit-example-test.c`를 참조하십시오.

/*
* Example of a parameterized test param_init() function that registers a dynamic
* array of parameters.
*/
static int example_param_init_dynamic_arr(struct kunit *test)
{
        size_t seq_size;
        int *fibonacci_params;

        kunit_info(test, "initializing parameterized test\n");

        seq_size = 6;
        fibonacci_params = make_fibonacci_params(test, seq_size);
        if (!fibonacci_params)
                return -ENOMEM;
        /*
        * Passes the dynamic parameter array information to the parameterized test
        * context struct kunit. The array and its metadata will be stored in
        * test->parent->params_array. The array itself will be located in
        * params_data.params.
        */
        kunit_register_params_array(test, fibonacci_params, seq_size,
                                example_param_dynamic_arr_get_desc);
        return 0;
}

static struct kunit_case example_test_cases[] = {
        /*
         * Note how we pass kunit_array_gen_params() to use the array we
         * registered in example_param_init_dynamic_arr() to generate
         * parameters.
         */
        KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr,
                                   kunit_array_gen_params,
                                   example_param_init_dynamic_arr,
                                   example_param_exit_dynamic_arr),
        {}
};
Parameterized test의 parameter 공급 방식
방식등록 API적합한 경우
Static array macroKUNIT_ARRAY_PARAM 또는 KUNIT_ARRAY_PARAM_DESCCompile-time table을 간단히 순회
Custom generatorKUNIT_CASE_PARAM이전 값에서 다음 parameter를 계산
Runtime arraykunit_register_params_array와 KUNIT_CASE_PARAM_WITH_INITInit 중 동적 또는 static array 등록

세 가지 generator 구성의 선택 기준을 정리했습니다.

Parameterized test의 shared resource

751-924

Shared resource 추가

모든 parameter run은 parent `struct kunit` pointer로 접근할 수 있는 parameterized test context reference를 가집니다. 이 context는 test logic을 직접 실행하지 않고 shared resource container 역할을 합니다.

`KUNIT_CASE_PARAM_WITH_INIT`에 custom `param_init()`과 `param_exit()`을 전달하면 parameter run 사이에서 resource를 공유할 수 있습니다. 두 function은 각각 parameterized test 전과 후에 한 번 실행됩니다.

`param_init()` signature는 `int (*)(struct kunit *test)`이며 parameterized test context의 `resources` 또는 `priv` field에 resource를 추가하고 parameter array를 등록하거나 다른 초기화를 수행합니다.

`param_exit()` signature는 `void (*)(struct kunit *test)`이며 parameterized test가 관리하지 않아 자동 cleanup되지 않는 resource를 release하고 다른 종료 logic을 수행합니다.

두 callback은 내부적으로 parameterized test context를 받지만 test case function은 parameter run context를 받습니다. 따라서 test case에서 shared resource를 관리하고 접근하려면 `test->parent`를 사용해야 합니다.

Resource API로 할당한 shared resource를 찾을 때는 `kunit_find_resource()`에 `test->parent`를 전달합니다. 같은 원칙이 `kunit_kzalloc()`, `kunit_kmalloc_array()` 같은 API에도 적용됩니다. `Documentation/dev-tools/kunit/api/test.rst`와 `Documentation/dev-tools/kunit/api/resource.rst`를 참조하십시오.

참고: 각 parameter run 전에 실행되는 `suite->init()`은 parameter run context를 받습니다. 따라서 여기서 설정한 resource는 각 parameter run 뒤 cleanup됩니다.

다음은 Resource API를 사용하는 shared resource 예입니다. 전체 version은 `lib/kunit/kunit-example-test.c`에 있습니다.

static int example_resource_init(struct kunit_resource *res, void *context)
{
        ... /* Code that allocates memory and stores context in res->data. */
}

/* This function deallocates memory for the kunit_resource->data field. */
static void example_resource_free(struct kunit_resource *res)
{
        kfree(res->data);
}

/* This match function locates a test resource based on defined criteria. */
static bool example_resource_alloc_match(struct kunit *test, struct kunit_resource *res,
                                         void *match_data)
{
        return res->data && res->free == example_resource_free;
}

/* Function to initialize the parameterized test. */
static int example_param_init(struct kunit *test)
{
        int ctx = 3; /* Data to be stored. */
        void *data = kunit_alloc_resource(test, example_resource_init,
                                          example_resource_free,
                                          GFP_KERNEL, &ctx);
        if (!data)
                return -ENOMEM;
        kunit_register_params_array(test, example_params_array,
                                    ARRAY_SIZE(example_params_array));
        return 0;
}

/* Example test that uses shared resources in test->resources. */
static void example_params_test_with_init(struct kunit *test)
{
        int threshold;
        const struct example_param *param = test->param_value;
        /*  Here we pass test->parent to access the parameterized test context. */
        struct kunit_resource *res = kunit_find_resource(test->parent,
                                                         example_resource_alloc_match,
                                                         NULL);

        threshold = *((int *)res->data);
        KUNIT_ASSERT_LE(test, param->value, threshold);
        kunit_put_resource(res);
}

static struct kunit_case example_test_cases[] = {
        KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params,
                                   example_param_init, NULL),
        {}
};

`example_param_init`은 resource를 할당하고 parameter array를 등록합니다. 각 test run은 parent context에서 match되는 resource를 찾아 threshold를 읽고 현재 parameter가 threshold 이하인지 확인한 뒤 reference를 release합니다.

KUnit Resource API 대신 `test->parent->priv`에 resource를 두는 가벼운 방법도 있습니다. 복잡한 resource management가 필요하지 않을 때 적합합니다.

`param_init()`과 `param_exit()` 안에서는 parameterized test context를 직접 받으므로 `test->priv`를 사용합니다. Test case에서는 parent context로 올라가 `test->parent->priv`로 같은 resource에 접근해야 합니다.

Parameter run 사이에서 유지하려면 `test->parent->priv` resource를 memory에 할당해야 합니다. KUnit memory allocation API를 사용하면 parameterized test가 관리하는 memory가 되어 전체 parameterized test 종료 뒤 자동 cleanup됩니다.

다음은 `priv` field를 사용하는 예입니다.

static const struct example_param {
        int value;
} example_params_array[] = {
        { .value = 3, },
        { .value = 2, },
        { .value = 1, },
        { .value = 0, },
};

/* Initialize the parameterized test context. */
static int example_param_init_priv(struct kunit *test)
{
        int ctx = 3; /* Data to be stored. */
        int arr_size = ARRAY_SIZE(example_params_array);

        /*
         * Allocate memory using kunit_kzalloc(). Since the `param_init`
         * function receives the parameterized test context, this memory
         * allocation will be scoped to the lifetime of the parameterized test.
         */
        test->priv = kunit_kzalloc(test, sizeof(int), GFP_KERNEL);

        /* Assign the context value to test->priv.*/
        *((int *)test->priv) = ctx;

        /* Register the parameter array. */
        kunit_register_params_array(test, example_params_array, arr_size, NULL);
        return 0;
}

static void example_params_test_with_init_priv(struct kunit *test)
{
        int threshold;
        const struct example_param *param = test->param_value;

        /* By design, test->parent will not be NULL. */
        KUNIT_ASSERT_NOT_NULL(test, test->parent);

        /* Here we use test->parent->priv to access the shared resource. */
        threshold = *(int *)test->parent->priv;

        KUNIT_ASSERT_LE(test, param->value, threshold);
}

static struct kunit_case example_tests[] = {
        KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_priv,
                                   kunit_array_gen_params,
                                   example_param_init_priv, NULL),
        {}
};

Init은 `kunit_kzalloc()`으로 parameterized test lifetime에 속하는 threshold를 할당하고 parameter array를 등록합니다. 각 run은 `test->parent`가 NULL이 아님을 확인한 뒤 parent `priv`에서 threshold를 읽습니다.

Parameterized test context 계층
Parameterized test context모든 run이 공유하는 parent struct kunit
param_initShared resources, priv와 parameter array 준비
Parameter run context각 run마다 독립적인 struct kunit
test->parentRun에서 shared context로 접근
param_exit전체 parameterized test 뒤 shared resource 정리

전체 test와 개별 run의 resource lifetime과 접근 경로를 구분했습니다.

Memory allocation과 cleanup action

925-1001

Memory 할당

일반 code에서 `kzalloc`을 사용할 자리에 `kunit_kzalloc`을 사용하면 test가 끝날 때 KUnit이 memory를 해제합니다.

따라서 `KUNIT_ASSERT_EQ` 같은 macro로 test에서 일찍 나가더라도 `kfree` 호출을 잊을 걱정이 없습니다.

void example_test_allocation(struct kunit *test)
{
        char *buffer = kunit_kzalloc(test, 16, GFP_KERNEL);
        /* Ensure allocation succeeded. */
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);

        KUNIT_ASSERT_STREQ(test, buffer, "");
}

Cleanup action 등록

`kunit_kzalloc` 이상의 cleanup이 필요하면 custom deferred action을 등록할 수 있습니다. Test가 정상 종료되든 assertion failure로 종료되든 실행되는 cleanup function입니다.

Action은 return value가 없고 하나의 `void *` context argument를 받는 단순 function입니다. Python과 Go test의 cleanup function, defer를 지원하는 language의 defer statement, 일부 RAII language의 destructor와 같은 역할을 합니다.

Global list에서 object를 unregister하거나 file과 다른 resource를 닫고 resource를 해제할 때 유용합니다.

static void cleanup_device(void *ctx)
{
        struct device *dev = (struct device *)ctx;

        device_unregister(dev);
}

void example_device_test(struct kunit *test)
{
        struct my_device dev;

        device_register(&dev);

        kunit_add_action(test, &cleanup_device, &dev);
}

`device_unregister`처럼 pointer 크기 argument 하나만 받는 function은 `KUNIT_DEFINE_ACTION_WRAPPER()` macro로 wrapper를 자동 생성할 수 있습니다.

KUNIT_DEFINE_ACTION_WRAPPER(device_unregister, device_unregister_wrapper, struct device *);
kunit_add_action(test, &device_unregister_wrapper, &dev);

Function pointer cast는 Control Flow Integrity, 즉 CFI를 깨뜨리므로 `kunit_action_t`로 수동 casting하지 말고 wrapper macro를 사용해야 합니다.

System memory 부족 같은 이유로 `kunit_add_action`이 실패할 수 있습니다. 대신 `kunit_add_action_or_reset`을 사용하면 defer할 수 없을 때 action을 즉시 실행합니다.

Cleanup 호출 시점을 더 세밀하게 제어하려면 `kunit_release_action`으로 일찍 실행하거나 `kunit_remove_action`으로 완전히 취소할 수 있습니다.

KUnit cleanup 선택
상황API동작
Test-scoped memorykunit_kzallocTest 종료 시 자동 free
일반 cleanupkunit_add_actionTest exit에서 deferred action 실행
등록 실패도 처리kunit_add_action_or_resetDefer 실패 시 즉시 action 실행
조기 cleanupkunit_release_action등록한 action을 지금 실행
Cleanup 취소kunit_remove_action등록한 action 제거

Resource 종류와 필요한 lifetime 제어에 맞는 API를 정리했습니다.

Static function 테스트

1002-1055

Static function 테스트

Static function을 test 외부에 항상 노출하지 않고 검사하려면 symbol을 조건부 export할 수 있습니다. KUnit이 활성화된 경우 symbol을 노출하고 그렇지 않을 때는 static으로 유지합니다.

/* In the file containing functions to test "my_file.c" */

#include <kunit/visibility.h>
#include <my_file.h>
...
VISIBLE_IF_KUNIT int do_interesting_thing()
{
...
}
EXPORT_SYMBOL_IF_KUNIT(do_interesting_thing);

/* In the header file "my_file.h" */

#if IS_ENABLED(CONFIG_KUNIT)
        int do_interesting_thing(void);
#endif

/* In the KUnit test file "my_file_test.c" */

#include <kunit/visibility.h>
#include <my_file.h>
...
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
...
// Use do_interesting_thing() in tests

Production source는 `VISIBLE_IF_KUNIT`과 `EXPORT_SYMBOL_IF_KUNIT`으로 function을 조건부 노출합니다. Header는 `IS_ENABLED(CONFIG_KUNIT)`일 때 declaration을 제공하고 test module은 `MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING")`로 namespace를 import합니다.

전체 예는 `https://lore.kernel.org/all/[email protected]/` patch를 참조하십시오.

대안으로 `.c` file 끝에서 test file을 조건부 `#include`할 수 있습니다. 권장하지 않지만 필요한 경우 동작합니다.

/* In "my_file.c" */

static int do_interesting_thing();

#ifdef CONFIG_MY_KUNIT_TEST
#include "my_kunit_test.c"
#endif

Test-only code 주입

1056-1074

Test-only code 주입

앞의 조건부 노출 방식과 비슷하게 test-specific logic을 추가할 수 있습니다.

/* In my_file.h */

#ifdef CONFIG_MY_KUNIT_TEST
/* Defined in my_kunit_test.c */
void test_only_hook(void);
#else
void test_only_hook(void) { }
#endif

`CONFIG_MY_KUNIT_TEST`가 활성화되면 test file이 정의한 `test_only_hook()`을 사용하고 그렇지 않으면 빈 implementation을 사용합니다.

다음 절의 current `kunit_test` 접근 방법을 결합하면 test-only code를 더 유용하게 만들 수 있습니다.

현재 test context 접근

1075-1134

현재 test 접근

Fake function implementation을 제공하거나 error handler 안에서 현재 test를 실패시키는 경우처럼 test file 밖에서 test-only code를 호출해야 할 수 있습니다.

`task_struct`의 `kunit_test` field를 `kunit/test-bug.h`의 `kunit_get_current_test()` function으로 접근할 수 있습니다.

KUnit이 활성화되지 않았거나 현재 task에서 test가 실행 중이 아니면 `kunit_get_current_test()`는 NULL을 반환하므로 언제나 안전하게 호출할 수 있습니다. No-op 또는 static key check로 compile되어 test가 없을 때 performance impact는 무시할 정도입니다.

다음은 이를 사용한 `foo`의 mock implementation입니다.

#include <kunit/test-bug.h> /* for kunit_get_current_test */

struct test_data {
        int foo_result;
        int want_foo_called_with;
};

static int fake_foo(int arg)
{
        struct kunit *test = kunit_get_current_test();
        struct test_data *test_data = test->priv;

        KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
        return test_data->foo_result;
}

static void example_simple_test(struct kunit *test)
{
        /* Assume priv (private, a member used to pass test data from
         * the init function) is allocated in the suite's .init */
        struct test_data *test_data = test->priv;

        test_data->foo_result = 42;
        test_data->want_foo_called_with = 1;

        /* In a real test, we'd probably pass a pointer to fake_foo somewhere
         * like an ops struct, etc. instead of calling it directly. */
        KUNIT_EXPECT_EQ(test, fake_foo(1), 42);
}

예제는 init function에서 test로 data를 전달하기 위해 `struct kunit`의 `priv` member를 사용합니다. `priv`는 임의 user data를 담을 수 있는 pointer입니다. Concurrency 문제를 피하므로 static variable보다 권장됩니다.

더 유연한 방법으로 이름 있는 `kunit_resource`를 사용할 수 있습니다. 각 test는 string name을 가진 resource를 여러 개 둘 수 있어 helper function끼리 충돌하지 않고 resource를 만들 수 있습니다. Resource마다 cleanup function을 정의해 leak도 쉽게 피할 수 있습니다.

자세한 내용은 `Documentation/dev-tools/kunit/api/resource.rst`를 참조하십시오.

현재 test 실패 처리

1135-1165

현재 test 실패

현재 test를 실패시키려면 `<kunit/test-bug.h>`의 `kunit_fail_current_test(fmt, args...)`를 사용합니다. `<kunit/test.h>`를 include할 필요가 없습니다.

다음 예는 data structure에 추가 debug check를 활성화하는 option에서 잘못된 data를 발견하면 현재 KUnit test를 실패시킵니다.

#include <kunit/test-bug.h>

#ifdef CONFIG_EXTRA_DEBUG_CHECKS
static void validate_my_data(struct data *data)
{
        if (is_valid(data))
                return;

        kunit_fail_current_test("data %p is invalid", data);

        /* Normal, non-KUnit, error reporting code here. */
}
#else
static void my_debug_function(void) { }
#endif

KUnit이 활성화되지 않았거나 현재 task에서 실행 중인 test가 없으면 `kunit_fail_current_test()`는 아무 일도 하지 않으므로 안전하게 호출할 수 있습니다. No-op 또는 static key check로 compile되어 일반 실행의 performance impact는 무시할 정도입니다.

Fake device와 driver 관리

1166-1214

Fake device와 driver 관리

Driver 또는 driver와 상호작용하는 code를 검사할 때 많은 function이 `struct device`나 `struct device_driver`를 요구합니다. 개별 function을 검사하는 데 real device setup이 필요하지 않은 경우 fake device를 사용할 수 있습니다.

KUnit은 내부 type이 `struct kunit_device`이고 special `kunit_bus`에 연결되는 fake device 생성 및 관리 helper를 제공합니다. 이 device들은 `Documentation/driver-api/driver-model/devres.rst`의 managed device resource, 즉 devres를 지원합니다.

KUnit-managed `struct device_driver`는 `kunit_driver_create()`로 만듭니다. 주어진 이름으로 `kunit_bus`에 driver를 만들며 test 종료 시 자동 destroy됩니다. 필요하면 `driver_unregister()`로 직접 제거할 수도 있습니다.

`kunit_device_register()`는 `kunit_driver_create()`가 만든 새 KUnit-managed driver를 사용해 fake device를 생성하고 등록합니다. 특정 non-KUnit-managed driver를 제공하려면 `kunit_device_register_with_driver()`를 사용합니다.

Managed fake device는 test 종료 시 자동 cleanup되며 `kunit_device_unregister()`로 일찍 제거할 수도 있습니다.

Device가 실제 platform device가 아니라면 `root_device_register()`보다 KUnit device를 사용하고 `platform_device_register()` 대신에도 KUnit device를 사용해야 합니다.

#include <kunit/device.h>

static void test_my_device(struct kunit *test)
{
        struct device *fake_device;
        const char *dev_managed_string;

        // Create a fake device.
        fake_device = kunit_device_register(test, "my_device");
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_device)

        // Pass it to functions which need a device.
        dev_managed_string = devm_kstrdup(fake_device, "Hello, World!");

        // Everything is cleaned up automatically when the test ends.
}

예제는 `kunit_device_register()`로 fake device를 만들고 device가 필요한 function에 전달합니다. `devm_kstrdup`로 만든 managed string을 포함한 모든 resource는 test 종료 시 자동 cleanup됩니다.