mirror of https://gitee.com/openkylin/linux.git
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
|
Organization of this document
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
This document is organized into two main sections: Testing and Isolating
|
This document is organized into two main sections: Testing and Common Patterns.
|
||||||
Behavior. The first covers what unit tests are and how to use KUnit to write
|
The first covers what unit tests are and how to use KUnit to write them. The
|
||||||
them. The second covers how to use KUnit to isolate code and make it possible
|
second covers common testing patterns, e.g. how to isolate code and make it
|
||||||
to unit test code that was otherwise un-unit-testable.
|
possible to unit test code that was otherwise un-unit-testable.
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
=======
|
=======
|
||||||
|
@ -218,8 +218,11 @@ test was built in or not).
|
||||||
|
|
||||||
For more information on these types of things see the :doc:`api/test`.
|
For more information on these types of things see the :doc:`api/test`.
|
||||||
|
|
||||||
|
Common Patterns
|
||||||
|
===============
|
||||||
|
|
||||||
Isolating Behavior
|
Isolating Behavior
|
||||||
==================
|
------------------
|
||||||
|
|
||||||
The most important aspect of unit testing that other forms of testing do not
|
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.
|
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.
|
at compile time.
|
||||||
|
|
||||||
Classes
|
Classes
|
||||||
-------
|
~~~~~~~
|
||||||
|
|
||||||
Classes are not a construct that is built into the C programming language;
|
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
|
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);
|
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:
|
||||||
|
|
||||||
KUnit on non-UML architectures
|
KUnit on non-UML architectures
|
||||||
|
|
Loading…
Reference in New Issue