diff options
author | Daniel Latypov <dlatypov@google.com> | 2020-11-24 01:57:59 +0300 |
---|---|---|
committer | Shuah Khan <skhan@linuxfoundation.org> | 2020-12-02 01:30:06 +0300 |
commit | 1f0e943df68ab407f523d9f47d96a535686a2293 (patch) | |
tree | ed2c4d133a6f280f7b1ab69ab148e7a078c101b3 /Documentation/dev-tools | |
parent | f3ed003e64fe7faecbe4c34bd2a1f5571a23f05a (diff) | |
download | linux-1f0e943df68ab407f523d9f47d96a535686a2293.tar.xz |
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>
Diffstat (limited to 'Documentation/dev-tools')
-rw-r--r-- | Documentation/dev-tools/kunit/usage.rst | 83 |
1 files changed, 77 insertions, 6 deletions
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index 9c28c518e6a3..d9fdc14f0677 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -15,10 +15,10 @@ project, see :doc:`start`. Organization of this document ============================= -This document is organized into two main sections: Testing and Isolating -Behavior. The first covers what unit tests are and how to use KUnit to write -them. The second covers how to use KUnit to isolate code and make it possible -to unit test code that was otherwise un-unit-testable. +This document is organized into two main sections: Testing and Common Patterns. +The first covers what unit tests are and how to use KUnit to write them. The +second covers common testing patterns, e.g. how to isolate code and make it +possible to unit test code that was otherwise un-unit-testable. Testing ======= @@ -218,8 +218,11 @@ test was built in or not). For more information on these types of things see the :doc:`api/test`. +Common Patterns +=============== + Isolating Behavior -================== +------------------ The most important aspect of unit testing that other forms of testing do not 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 at compile time. Classes -------- +~~~~~~~ Classes are not a construct that is built into the C programming language; 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``: destroy_eeprom_buffer(ctx->eeprom_buffer); } +Testing against multiple inputs +------------------------------- + +Testing just a few inputs might not be enough to have confidence that the code +works correctly, e.g. for a hash function. + +In such cases, it can be helpful to have a helper macro or function, e.g. this +fictitious example for ``sha1sum(1)`` + +.. code-block:: c + + /* Note: the cast is to satisfy overly strict type-checking. */ + #define TEST_SHA1(in, want) \ + sha1sum(in, out); \ + KUNIT_EXPECT_STREQ_MSG(test, (char *)out, want, "sha1sum(%s)", in); + + char out[40]; + TEST_SHA1("hello world", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"); + TEST_SHA1("hello world!", "430ce34d020724ed75a196dfc2ad67c77772d169"); + + +Note the use of ``KUNIT_EXPECT_STREQ_MSG`` to give more context when it fails +and make it easier to track down. (Yes, in this example, ``want`` is likely +going to be unique enough on its own). + +The ``_MSG`` variants are even more useful when the same expectation is called +multiple times (in a loop or helper function) and thus the line number isn't +enough to identify what failed, like below. + +In some cases, it can be helpful to write a *table-driven test* instead, e.g. + +.. code-block:: c + + 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, (char *)out, cases[i].sha1, + "sha1sum(%s)", cases[i].str); + } + + +There's more boilerplate involved, but it can: + +* be more readable when there are multiple inputs/outputs thanks to field names, + + * E.g. see ``fs/ext4/inode-test.c`` for an example of both. +* reduce duplication if test cases can be shared across multiple tests. + + * E.g. if we wanted to also test ``sha256sum``, we could add a ``sha256`` + field and reuse ``cases``. + .. _kunit-on-non-uml: KUnit on non-UML architectures |