KUnit 架构¶
KUnit 架构分为两部分
内核内测试框架¶
内核测试库支持使用 KUnit 以 C 编写的 KUnit 测试。这些 KUnit 测试是内核代码。KUnit 执行以下任务
组织测试
报告测试结果
提供测试实用程序
测试用例¶
测试用例是 KUnit 中的基本单元。 KUnit 测试用例被组织成套件。 KUnit 测试用例是一个函数,其类型签名为 void (*)(struct kunit *test)
。这些测试用例函数包装在一个名为 struct kunit_case
的结构中。
每个 KUnit 测试用例都会收到一个 struct kunit
上下文对象,该对象跟踪正在运行的测试。 KUnit 断言宏和其他 KUnit 实用程序使用 struct kunit
上下文对象。作为一个例外,有两个字段
->priv
:setup 函数可以使用它来存储任意测试用户数据。->param_value
:它包含参数值,可以在参数化测试中检索该参数值。
测试套件¶
一个 KUnit 套件包括一系列测试用例。 KUnit 套件由 struct kunit_suite
表示。例如
static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_test_foo),
KUNIT_CASE(example_test_bar),
KUNIT_CASE(example_test_baz),
{}
};
static struct kunit_suite example_test_suite = {
.name = "example",
.init = example_test_init,
.exit = example_test_exit,
.test_cases = example_test_cases,
};
kunit_test_suite(example_test_suite);
在上面的示例中,测试套件 example_test_suite
运行测试用例 example_test_foo
、example_test_bar
和 example_test_baz
。在运行测试之前,调用 example_test_init
,在运行测试之后,调用 example_test_exit
。 kunit_test_suite(example_test_suite)
将测试套件注册到 KUnit 测试框架。
执行器¶
KUnit 执行器可以列出并运行启动时内置的 KUnit 测试。测试套件存储在名为 .kunit_test_suites
的链接器部分中。有关代码,请参见 include/asm-generic/vmlinux.lds.h 中的 KUNIT_TABLE()
宏定义。链接器部分由指向 struct kunit_suite
的指针数组组成,并由 kunit_test_suites()
宏填充。 KUnit 执行器迭代链接器部分数组,以便运行编译到内核中的所有测试。
KUnit 套件内存图¶
在内核启动时,KUnit 执行器使用此部分的起始和结束地址来迭代并运行所有测试。有关执行器的实现,请参见 lib/kunit/executor.c。当作为模块构建时,kunit_test_suites()
宏定义了一个 module_init()
函数,该函数运行编译单元中的所有测试,而不是利用执行器。
在 KUnit 测试中,某些错误类不影响其他测试或内核的其他部分,每个 KUnit 用例都在单独的线程上下文中执行。 请参见 lib/kunit/try-catch.c 中的 kunit_try_catch_run()
函数。
断言宏¶
KUnit 测试使用期望/断言来验证状态。 所有期望/断言的格式为:KUNIT_{EXPECT|ASSERT}_<op>[_MSG](kunit, property[, message])
{EXPECT|ASSERT}
确定检查是断言还是期望。 如果发生故障,测试流程的差异如下对于期望,测试被标记为失败,并且记录失败。
另一方面,断言失败会导致测试用例立即终止。
断言调用函数:
void __noreturn __kunit_abort(struct kunit *)
。__kunit_abort
调用函数:void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)
。kunit_try_catch_throw
调用函数:void kthread_complete_and_exit(struct completion *, long) __noreturn;
并终止特殊的线程上下文。
<op>
表示具有以下选项的检查:TRUE
(提供的属性具有布尔值“true”),EQ
(两个提供的属性相等),NOT_ERR_OR_NULL
(提供的指针不为空且不包含“err”值)。[_MSG]
在失败时打印自定义消息。
测试结果报告¶
KUnit 以 KTAP 格式打印测试结果。 KTAP 基于 TAP14,请参阅 内核测试通用协议 (KTAP),版本 1。 KTAP 可与 KUnit 和 Kselftest 配合使用。 KUnit 执行器将 KTAP 结果打印到 dmesg 和 debugfs(如果已配置)。
参数化测试¶
每个 KUnit 参数化测试都与一个参数集合相关联。该测试被多次调用,每个参数值调用一次,并且该参数存储在 param_value
字段中。测试用例包括一个 KUNIT_CASE_PARAM()
宏,该宏接受一个生成器函数。生成器函数传递先前的参数,并返回下一个参数。它还包括一个用于生成基于数组的常见用例生成器的宏。
kunit_tool (命令行测试工具)¶
kunit_tool
是一个 Python 脚本,位于 tools/testing/kunit/kunit.py
中。 它用于配置、构建、执行、解析测试结果,并以正确的顺序运行所有先前的命令(即,配置、构建、执行和解析)。 您可以选择两种方式来运行 KUnit 测试:构建启用 KUnit 的内核并手动解析结果(请参阅 不使用 kunit_tool 运行测试),或者使用 kunit_tool
(请参阅 使用 kunit_tool 运行测试)。
configure
命令从.kunitconfig
文件(以及任何特定于体系结构的选择)生成内核.config
。qemu_configs
文件夹中提供的 Python 脚本(例如,tools/testing/kunit/qemu configs/powerpc.py
)包含特定体系结构的附加配置选项。 它解析现有的.config
文件和.kunitconfig
文件,以确保.config
是.kunitconfig
的超集。 如果不是,它将合并这两个文件并运行make olddefconfig
以重新生成.config
文件。 然后,它检查.config
是否已成为超集。 这验证了所有 Kconfig 依赖项是否在文件.kunitconfig
中正确指定。kunit_config.py
脚本包含用于解析 Kconfig 的代码。 运行make olddefconfig
的代码是kunit_kernel.py
脚本的一部分。 您可以通过以下命令调用此命令:./tools/testing/kunit/kunit.py config
并生成一个.config
文件。build
使用必需的选项(取决于体系结构和一些选项,例如:build_dir)在内核树上运行make
并报告任何错误。 要从当前的.config
构建 KUnit 内核,可以使用build
参数:./tools/testing/kunit/kunit.py build
。exec
命令直接(使用用户模式 Linux 配置)或通过模拟器(例如 QEMU)执行内核结果。 它使用标准输出 (stdout) 从日志中读取结果,并将它们传递给parse
进行解析。 如果您已经构建了一个带有内置 KUnit 测试的内核,则可以运行该内核并使用exec
参数显示测试结果:./tools/testing/kunit/kunit.py exec
。parse
从内核日志中提取 KTAP 输出,解析测试结果,并打印摘要。 对于失败的测试,将包含任何诊断输出。