mirror of
https://github.com/torvalds/linux.git
synced 2024-12-12 14:12:51 +00:00
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>
This commit is contained in:
parent
f3ed003e64
commit
1f0e943df6
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user