Skip to content

Commit 1f0e943

Browse files
dlatypovshuahkh
authored andcommitted
Documentation: kunit: provide guidance for testing many inputs
usage.rst goes into a detailed section about faking out classes, but currently lacks wording about how one might idiomatically test a range of inputs. Add a new chapter for "Common Patterns" and group "Isolating behvaior" and this new section under there. Give an example of how one might test a hash function via macros/helper funcs and a table-driven test and very briefly discuss pros and cons. Also highlight the KUNIT_EXPECT_*_MSG() variants (that aren't mentioned elsewhere [1]) which are particularly useful in these situations. It is also criminally underused at the moment, only appearing in 2 tests (both written by people involved in KUnit). [1] not even on https://www.kernel.org/doc/html/latest/dev-tools/kunit/api/test.html Signed-off-by: Daniel Latypov <dlatypov@google.com> Reviewed-by: Brendan Higgins <brendanhiggins@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
1 parent f3ed003 commit 1f0e943

File tree

1 file changed

+77
-6
lines changed

1 file changed

+77
-6
lines changed

Documentation/dev-tools/kunit/usage.rst

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ project, see :doc:`start`.
1515
Organization of this document
1616
=============================
1717

18-
This document is organized into two main sections: Testing and Isolating
19-
Behavior. The first covers what unit tests are and how to use KUnit to write
20-
them. The second covers how to use KUnit to isolate code and make it possible
21-
to unit test code that was otherwise un-unit-testable.
18+
This document is organized into two main sections: Testing and Common Patterns.
19+
The first covers what unit tests are and how to use KUnit to write them. The
20+
second covers common testing patterns, e.g. how to isolate code and make it
21+
possible to unit test code that was otherwise un-unit-testable.
2222

2323
Testing
2424
=======
@@ -218,8 +218,11 @@ test was built in or not).
218218

219219
For more information on these types of things see the :doc:`api/test`.
220220

221+
Common Patterns
222+
===============
223+
221224
Isolating Behavior
222-
==================
225+
------------------
223226

224227
The most important aspect of unit testing that other forms of testing do not
225228
provide is the ability to limit the amount of code under test to a single unit.
@@ -233,7 +236,7 @@ implementer, and architecture-specific functions which have definitions selected
233236
at compile time.
234237

235238
Classes
236-
-------
239+
~~~~~~~
237240

238241
Classes are not a construct that is built into the C programming language;
239242
however, it is an easily derived concept. Accordingly, pretty much every project
@@ -451,6 +454,74 @@ We can now use it to test ``struct eeprom_buffer``:
451454
destroy_eeprom_buffer(ctx->eeprom_buffer);
452455
}
453456
457+
Testing against multiple inputs
458+
-------------------------------
459+
460+
Testing just a few inputs might not be enough to have confidence that the code
461+
works correctly, e.g. for a hash function.
462+
463+
In such cases, it can be helpful to have a helper macro or function, e.g. this
464+
fictitious example for ``sha1sum(1)``
465+
466+
.. code-block:: c
467+
468+
/* Note: the cast is to satisfy overly strict type-checking. */
469+
#define TEST_SHA1(in, want) \
470+
sha1sum(in, out); \
471+
KUNIT_EXPECT_STREQ_MSG(test, (char *)out, want, "sha1sum(%s)", in);
472+
473+
char out[40];
474+
TEST_SHA1("hello world", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
475+
TEST_SHA1("hello world!", "430ce34d020724ed75a196dfc2ad67c77772d169");
476+
477+
478+
Note the use of ``KUNIT_EXPECT_STREQ_MSG`` to give more context when it fails
479+
and make it easier to track down. (Yes, in this example, ``want`` is likely
480+
going to be unique enough on its own).
481+
482+
The ``_MSG`` variants are even more useful when the same expectation is called
483+
multiple times (in a loop or helper function) and thus the line number isn't
484+
enough to identify what failed, like below.
485+
486+
In some cases, it can be helpful to write a *table-driven test* instead, e.g.
487+
488+
.. code-block:: c
489+
490+
int i;
491+
char out[40];
492+
493+
struct sha1_test_case {
494+
const char *str;
495+
const char *sha1;
496+
};
497+
498+
struct sha1_test_case cases[] = {
499+
{
500+
.str = "hello world",
501+
.sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
502+
},
503+
{
504+
.str = "hello world!",
505+
.sha1 = "430ce34d020724ed75a196dfc2ad67c77772d169",
506+
},
507+
};
508+
for (i = 0; i < ARRAY_SIZE(cases); ++i) {
509+
sha1sum(cases[i].str, out);
510+
KUNIT_EXPECT_STREQ_MSG(test, (char *)out, cases[i].sha1,
511+
"sha1sum(%s)", cases[i].str);
512+
}
513+
514+
515+
There's more boilerplate involved, but it can:
516+
517+
* be more readable when there are multiple inputs/outputs thanks to field names,
518+
519+
* E.g. see ``fs/ext4/inode-test.c`` for an example of both.
520+
* reduce duplication if test cases can be shared across multiple tests.
521+
522+
* E.g. if we wanted to also test ``sha256sum``, we could add a ``sha256``
523+
field and reuse ``cases``.
524+
454525
.. _kunit-on-non-uml:
455526

456527
KUnit on non-UML architectures

0 commit comments

Comments
 (0)