入门¶
本页包含 kunit_tool 和 KUnit 框架的概述,介绍如何运行现有测试,然后如何编写简单的测试用例,并涵盖用户首次使用 KUnit 时遇到的常见问题。
安装依赖项¶
KUnit 具有与 Linux 内核相同的依赖项。只要你可以构建内核,就可以运行 KUnit。
使用 kunit_tool 运行测试¶
kunit_tool 是一个 Python 脚本,它配置并构建内核、运行测试并格式化测试结果。从内核存储库中,你可以运行 kunit_tool
./tools/testing/kunit/kunit.py run
注意
你可能会看到以下错误:“源代码树不干净,请运行‘make ARCH=um mrproper’”
发生这种情况是因为内部 kunit.py 在命令 make O=output/dir
中通过参数 --build_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
中设置。如果未包含所用选项的依赖项,它将警告你。
有多种方法可以自定义配置
编辑
.kunit/.kunitconfig
。该文件应包含运行所需测试所需的 kconfig 选项列表,包括其依赖项。你可能想要从.kunitconfig
中删除 CONFIG_KUNIT_ALL_TESTS,因为它将启用许多你可能不需要的其他测试。如果需要在 UML 以外的架构上运行,请参阅 在 QEMU 上运行测试。在
.kunit/.kunitconfig
之上启用其他 kconfig 选项。例如,要包含内核的链表测试,你可以运行./tools/testing/kunit/kunit.py run \ --kconfig_add CONFIG_LIST_KUNIT_TEST=y
从树中提供一个或多个 .kunitconfig 文件的路径。例如,要仅运行
FAT_FS
和EXT4
测试,你可以运行./tools/testing/kunit/kunit.py run \ --kunitconfig ./fs/fat/.kunitconfig \ --kunitconfig ./fs/ext4/.kunitconfig
如果你更改
.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) 中模式的说明)来选择在启动时执行的测试。如果过滤器中存在 "."
(句点),则将其解释为测试套件名称和测试用例之间的分隔符,否则,将其解释为测试套件的名称。例如,假设我们正在使用默认配置
告知测试套件的名称,例如
"kunit_executor_test"
,以运行它包含的每个测试用例./tools/testing/kunit/kunit.py run "kunit_executor_test"
告知以其测试套件为前缀的测试用例的名称,例如
"example.example_simple_test"
,以专门运行该测试用例./tools/testing/kunit/kunit.py run "example.example_simple_test"
使用通配符 (
*?[
) 运行与模式匹配的任何测试用例,例如"*.*64*"
以在任何测试套件中运行名称中包含"64"
的测试用例./tools/testing/kunit/kunit.py run "*.*64*"
在没有 KUnit 包装器的情况下运行测试¶
如果你不想使用 KUnit 包装器(例如:你希望被测试的代码与其他系统集成,或使用不同的/不支持的架构或配置),则可以将 KUnit 包含在任何内核中,并且可以手动读出和解析结果。
注意
不应在生产环境中启用 CONFIG_KUNIT
。启用 KUnit 会禁用内核地址空间布局随机化 (KASLR),并且测试可能会以不适合生产的方式影响内核的状态。
配置内核¶
要启用 KUnit 本身,你需要启用 CONFIG_KUNIT
Kconfig 选项(在 menuconfig
中的“内核黑客/内核测试和覆盖率”下)。从那里,你可以启用任何 KUnit 测试。它们的配置选项通常以 _KUNIT_TEST
结尾。
KUnit 和 KUnit 测试可以编译为模块。模块中的测试将在模块加载时运行。
运行测试(不使用 KUnit 包装器)¶
构建并运行你的内核。在内核日志中,测试输出以 TAP 格式打印出来。默认情况下,只有在内置 KUnit/测试时才会发生这种情况。否则,将需要加载该模块。
注意
一些行和/或数据可能会散布在 TAP 输出中。
编写你的第一个测试¶
在你的内核仓库中,让我们添加一些可以测试的代码。
创建一个文件
drivers/misc/example.h
,其中包含
int misc_example_add(int left, int right);
创建一个文件
drivers/misc/example.c
,其中包含
#include <linux/errno.h>
#include "example.h"
int misc_example_add(int left, int right)
{
return left + right;
}
将以下行添加到
drivers/misc/Kconfig
config MISC_EXAMPLE
bool "My example"
将以下行添加到
drivers/misc/Makefile
obj-$(CONFIG_MISC_EXAMPLE) += example.o
现在我们准备编写测试用例了。
在
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");
将以下行添加到
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。
将以下行添加到
drivers/misc/Makefile
obj-$(CONFIG_MISC_EXAMPLE_TEST) += example_test.o
将以下行添加到
.kunit/.kunitconfig
CONFIG_MISC_EXAMPLE=y
CONFIG_MISC_EXAMPLE_TEST=y
运行测试
./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 测试的更多信息(包括测试不同内容的一些常用技术),请参阅 编写测试