开始使用¶
本页面包含 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 用于编译内核,或者
按名称筛选测试 以专门选择要运行的已编译测试。
自定义 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
中的 Kernel Hacking/Kernel Testing and Coverage 下)。 从那里,您可以启用任何 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 测试的更多信息(包括一些用于测试不同事物的常用技术),请参阅 编写测试