开始使用

本页面包含 kunit_tool 和 KUnit 框架的概述,介绍如何运行现有测试,以及如何编写一个简单的测试用例,并涵盖用户首次使用 KUnit 时遇到的常见问题。

安装依赖

KUnit 具有与 Linux 内核相同的依赖项。 只要您可以构建内核,就可以运行 KUnit。

使用 kunit_tool 运行测试

kunit_tool 是一个 Python 脚本,用于配置和构建内核、运行测试以及格式化测试结果。 从内核存储库中,您可以运行 kunit_tool

./tools/testing/kunit/kunit.py run

注意

您可能会看到以下错误:“The source tree is not clean, please run ‘make ARCH=um mrproper’”(源代码树不干净,请运行 ‘make ARCH=um mrproper’)

发生这种情况是因为 kunit.py 在内部通过参数 --build_dir 在命令 make O=output/dir 中将 .kunit(默认选项)指定为构建目录。 因此,在启动树外构建之前,必须清理源代码树。

admin-guide 的“内核构建目录”部分中也提到了相同的注意事项,即它的使用,它必须用于 make 的所有调用。 好消息是,它确实可以通过运行 make ARCH=um mrproper 来解决,但请注意,这将删除当前配置和所有生成的文件。

如果一切正常,您应该看到以下内容

Configuring KUnit Kernel ...
Building KUnit Kernel ...
Starting KUnit Kernel ...

测试将通过或失败。

注意

因为这是第一次构建大量源文件,所以 Building KUnit Kernel 步骤可能需要一段时间。

有关此包装器的详细信息,请参阅: 使用 kunit_tool 运行测试

选择要运行的测试

默认情况下,kunit_tool 使用最小配置运行所有可访问的测试,即使用 kconfig 选项的大多数默认值。 但是,您可以通过以下方式选择要运行的测试:

自定义 Kconfig

.kunitconfig 的一个好的起点是 KUnit 默认配置。 如果您尚未运行 kunit.py run,则可以通过运行以下命令来生成它:

cd $PATH_TO_LINUX_REPO
tools/testing/kunit/kunit.py config
cat .kunit/.kunitconfig

注意

.kunitconfig 位于 kunit.py 使用的 --build_dir 中,默认情况下为 .kunit

在运行测试之前,kunit_tool 确保 .kunitconfig 中设置的所有配置选项都已在内核 .config 中设置。 如果您没有包含所用选项的依赖项,它会发出警告。

有很多方法可以自定义配置

  1. 编辑 .kunit/.kunitconfig。 该文件应包含运行所需测试所需的 kconfig 选项列表,包括它们的依赖项。 您可能需要从 .kunitconfig 中删除 CONFIG_KUNIT_ALL_TESTS,因为它会启用许多您可能不需要的其他测试。 如果您需要在 UML 以外的架构上运行,请参阅 在 QEMU 上运行测试

  2. .kunit/.kunitconfig 之上启用其他 kconfig 选项。 例如,要包含内核的链表测试,您可以运行

    ./tools/testing/kunit/kunit.py run \
            --kconfig_add CONFIG_LIST_KUNIT_TEST=y
    
  3. 从树中提供一个或多个 .kunitconfig 文件的路径。 例如,要仅运行 FAT_FSEXT4 测试,您可以运行

    ./tools/testing/kunit/kunit.py run \
            --kunitconfig ./fs/fat/.kunitconfig \
            --kunitconfig ./fs/ext4/.kunitconfig
    
  4. 如果您更改 .kunitconfig,kunit.py 将触发 .config 文件的重建。 但是您可以直接编辑 .config 文件,或使用 make menuconfig O=.kunit 等工具进行编辑。 只要它是 .kunitconfig 的超集,kunit.py 就不会覆盖您的更改。

注意

要在找到令人满意的配置后保存 .kunitconfig

make savedefconfig O=.kunit
cp .kunit/defconfig .kunit/.kunitconfig

按名称筛选测试

如果您想要比 Kconfig 可以提供的更具体的信息,还可以通过传递 glob 过滤器(阅读 manpage glob(7) 中关于模式的说明)来选择在启动时执行哪些测试。 如果过滤器中存在 "."(句点),则它将被解释为测试套件名称和测试用例之间的分隔符,否则,它将被解释为测试套件的名称。 例如,假设我们正在使用默认配置

  1. 通知测试套件的名称,如 "kunit_executor_test",以运行它包含的每个测试用例

    ./tools/testing/kunit/kunit.py run "kunit_executor_test"
    
  2. 通知测试用例的名称,以其测试套件作为前缀,如 "example.example_simple_test",以专门运行该测试用例

    ./tools/testing/kunit/kunit.py run "example.example_simple_test"
    
  3. 使用通配符 (*?[) 运行与模式匹配的任何测试用例,如 "*.*64*" 运行任何测试套件中名称包含 "64" 的测试用例

    ./tools/testing/kunit/kunit.py run "*.*64*"
    

不使用 KUnit 包装器运行测试

如果您不想使用 KUnit 包装器(例如:您希望被测代码与其他系统集成,或者使用不同/不受支持的架构或配置),则可以将 KUnit 包含在任何内核中,并且可以手动读取和解析结果。

注意

不应在生产环境中启用 CONFIG_KUNIT。 启用 KUnit 会禁用内核地址空间布局随机化 (KASLR),并且测试可能会以不适合生产的方式影响内核状态。

配置内核

要启用 KUnit 本身,您需要启用 CONFIG_KUNIT Kconfig 选项(在 menuconfig 中的 Kernel Hacking/Kernel Testing and Coverage 下)。 从那里,您可以启用任何 KUnit 测试。 它们通常具有以 _KUNIT_TEST 结尾的配置选项。

KUnit 和 KUnit 测试可以编译为模块。 模块中的测试将在加载模块时运行。

运行测试(不使用 KUnit 包装器)

构建并运行您的内核。 在内核日志中,测试输出以 TAP 格式打印出来。 默认情况下,只有在 KUnit/测试是内置的情况下才会发生这种情况。 否则,需要加载该模块。

注意

一些行和/或数据可能会散布在 TAP 输出中。

编写您的第一个测试

在您的内核存储库中,让我们添加一些可以测试的代码。

  1. 创建一个文件 drivers/misc/example.h,其中包括

int misc_example_add(int left, int right);
  1. 创建一个文件 drivers/misc/example.c,其中包括

#include <linux/errno.h>

#include "example.h"

int misc_example_add(int left, int right)
{
        return left + right;
}
  1. 将以下行添加到 drivers/misc/Kconfig

config MISC_EXAMPLE
        bool "My example"
  1. 将以下行添加到 drivers/misc/Makefile

obj-$(CONFIG_MISC_EXAMPLE) += example.o

现在我们准备编写测试用例了。

  1. drivers/misc/example_test.c 中添加以下测试用例

#include <kunit/test.h>
#include "example.h"

/* Define the test cases. */

static void misc_example_add_test_basic(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, 1, misc_example_add(1, 0));
        KUNIT_EXPECT_EQ(test, 2, misc_example_add(1, 1));
        KUNIT_EXPECT_EQ(test, 0, misc_example_add(-1, 1));
        KUNIT_EXPECT_EQ(test, INT_MAX, misc_example_add(0, INT_MAX));
        KUNIT_EXPECT_EQ(test, -1, misc_example_add(INT_MAX, INT_MIN));
}

static void misc_example_test_failure(struct kunit *test)
{
        KUNIT_FAIL(test, "This test never passes.");
}

static struct kunit_case misc_example_test_cases[] = {
        KUNIT_CASE(misc_example_add_test_basic),
        KUNIT_CASE(misc_example_test_failure),
        {}
};

static struct kunit_suite misc_example_test_suite = {
        .name = "misc-example",
        .test_cases = misc_example_test_cases,
};
kunit_test_suite(misc_example_test_suite);

MODULE_LICENSE("GPL");
  1. 将以下行添加到 drivers/misc/Kconfig

config MISC_EXAMPLE_TEST
        tristate "Test for my example" if !KUNIT_ALL_TESTS
        depends on MISC_EXAMPLE && KUNIT
        default KUNIT_ALL_TESTS

注意:如果您的测试不支持作为可加载模块构建(不鼓励),请将 tristate 替换为 bool,并依赖于 KUNIT=y 而不是 KUNIT。

  1. 将以下行添加到 drivers/misc/Makefile

obj-$(CONFIG_MISC_EXAMPLE_TEST) += example_test.o
  1. 将以下行添加到 .kunit/.kunitconfig

CONFIG_MISC_EXAMPLE=y
CONFIG_MISC_EXAMPLE_TEST=y
  1. 运行测试

./tools/testing/kunit/kunit.py run

您应该看到以下失败

...
[16:08:57] [PASSED] misc-example:misc_example_add_test_basic
[16:08:57] [FAILED] misc-example:misc_example_test_failure
[16:08:57] EXPECTATION FAILED at drivers/misc/example-test.c:17
[16:08:57]      This test never passes.
...

恭喜! 您刚刚编写了您的第一个 KUnit 测试。

下一步

如果您有兴趣使用 kunit.py 的一些更高级的功能,请查看 使用 kunit_tool 运行测试

如果您想在不使用 kunit.py 的情况下运行测试,请查看 不使用 kunit_tool 运行测试

有关编写 KUnit 测试的更多信息(包括一些用于测试不同事物的常用技术),请参阅 编写测试