123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- .. SPDX-License-Identifier: GPL-2.0
- ============================
- Tips For Writing KUnit Tests
- ============================
- Exiting early on failed expectations
- ------------------------------------
- ``KUNIT_EXPECT_EQ`` and friends will mark the test as failed and continue
- execution. In some cases, it's unsafe to continue and you can use the
- ``KUNIT_ASSERT`` variant to exit on failure.
- .. code-block:: c
- void example_test_user_alloc_function(struct kunit *test)
- {
- void *object = alloc_some_object_for_me();
- /* Make sure we got a valid pointer back. */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
- do_something_with_object(object);
- }
- Allocating memory
- -----------------
- Where you would use ``kzalloc``, you should prefer ``kunit_kzalloc`` instead.
- KUnit will ensure the memory is freed once the test completes.
- This is particularly useful since it lets you use the ``KUNIT_ASSERT_EQ``
- macros to exit early from a test without having to worry about remembering to
- call ``kfree``.
- Example:
- .. code-block:: c
- 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, "");
- }
- Testing static functions
- ------------------------
- If you don't want to expose functions or variables just for testing, one option
- is to conditionally ``#include`` the test file at the end of your .c file, e.g.
- .. code-block:: c
- /* In my_file.c */
- static int do_interesting_thing();
- #ifdef CONFIG_MY_KUNIT_TEST
- #include "my_kunit_test.c"
- #endif
- Injecting test-only code
- ------------------------
- Similarly to the above, it can be useful to add test-specific logic.
- .. code-block:: c
- /* 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
- This test-only code can be made more useful by accessing the current kunit
- test, see below.
- Accessing the current test
- --------------------------
- In some cases, you need to call test-only code from outside the test file, e.g.
- like in the example above or if you're providing a fake implementation of an
- ops struct.
- There is a ``kunit_test`` field in ``task_struct``, so you can access it via
- ``current->kunit_test``.
- Here's a slightly in-depth example of how one could implement "mocking":
- .. code-block:: c
- #include <linux/sched.h> /* for current */
- struct test_data {
- int foo_result;
- int want_foo_called_with;
- };
- static int fake_foo(int arg)
- {
- struct kunit *test = current->kunit_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 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);
- }
- Note: here we're able to get away with using ``test->priv``, but if you wanted
- something more flexible you could use a named ``kunit_resource``, see
- Documentation/dev-tools/kunit/api/test.rst.
- Failing the current test
- ------------------------
- But sometimes, you might just want to fail the current test. In that case, we
- have ``kunit_fail_current_test(fmt, args...)`` which is defined in ``<kunit/test-bug.h>`` and
- doesn't require pulling in ``<kunit/test.h>``.
- E.g. say we had an option to enable some extra debug checks on some data structure:
- .. code-block:: c
- #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
- Customizing error messages
- --------------------------
- Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG`` variant.
- These take a format string and arguments to provide additional context to the automatically generated error messages.
- .. code-block:: c
- 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);
- Alternatively, one can take full control over the error message by using ``KUNIT_FAIL()``, e.g.
- .. code-block:: c
- /* 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");
- Next Steps
- ==========
- * Optional: see the Documentation/dev-tools/kunit/usage.rst page for a more
- in-depth explanation of KUnit.
|