测试风格和命名

为了使查找、编写和使用 KUnit 测试尽可能简单,强烈建议按照以下准则对其进行命名和编写。 虽然可以编写不遵循这些规则的 KUnit 测试,但它们可能会破坏某些工具,可能与其他测试冲突,并且可能不会被测试系统自动运行。

建议您仅在以下情况下偏离这些准则

  1. 将已知名称的测试移植到 KUnit。

  2. 编写如果自动运行会导致严重问题的测试。 例如,非确定性地产生误报或误报,或者运行时间很长。

子系统、套件和测试

为了使测试易于查找,它们被分组到套件和子系统中。 测试套件是一组测试内核相关区域的测试。 子系统是一组测试内核子系统或驱动程序不同部分的测试套件。

子系统

每个测试套件都必须属于一个子系统。 子系统是一个或多个 KUnit 测试套件的集合,这些测试套件测试相同的驱动程序或内核的一部分。 测试子系统应与单个内核模块匹配。 如果要测试的代码无法编译为模块,在许多情况下,子系统应对应于源代码树中的目录或 MAINTAINERS 文件中的条目。 如果不确定,请遵循类似区域中测试设置的约定。

测试子系统应以正在测试的代码命名,要么以模块命名(如果可能),要么以正在测试的目录或文件命名。 测试子系统应进行命名,以避免在必要时产生歧义。

如果测试子系统名称有多个组成部分,则应使用下划线分隔。 除非我们实际上正在测试其他测试或 kunit 框架本身,否则不要在子系统名称中直接包含“test”或“kunit”。 例如,子系统可以称为

ext4

匹配模块和文件系统名称。

apparmor

匹配模块名称和 LSM 名称。

kasan

该工具的常用名称,路径的突出部分 mm/kasan

snd_hda_codec_hdmi

具有多个组成部分(sndhdacodechdmi),用下划线分隔。 匹配模块名称。

避免使用以下示例中所示的名称

linear-ranges

名称应使用下划线而不是破折号分隔单词。 首选 linear_ranges

qos-kunit-test

此名称应使用下划线,并且不应将“kunit-test”作为后缀。 qos 作为子系统名称也是不明确的,因为内核的多个部分都有一个 qos 子系统。 power_qos 会是一个更好的名字。

pc_parallel_port

相应的模块名称是 parport_pc,因此此子系统也应命名为 parport_pc

注意

KUnit API 和工具不明确了解子系统。 它们是一种对测试套件进行分类和命名模块的方式,为人们提供了一种简单、一致的方式来查找和运行测试。 这可能会在未来发生变化。

套件

KUnit 测试分组到测试套件中,这些套件涵盖正在测试的特定功能区域。 测试套件可以具有共享的初始化和关闭代码,这些代码在套件中的所有测试中运行。 并非所有子系统都需要拆分为多个测试套件(例如,简单的驱动程序)。

测试套件以它们所属的子系统命名。 如果子系统包含多个套件,则应将正在测试的特定区域附加到子系统名称,并用下划线分隔。

如果子系统内使用 KUnit 进行多种类型的测试(例如,单元测试和集成测试),则应将它们放入单独的套件中,并将测试类型作为套件名称中的最后一个元素。 除非这些测试实际存在,否则请避免在套件名称中使用 _test_unittest 或类似内容。

完整的测试套件名称(包括子系统名称)应指定为 kunit_suite 结构体的 .name 成员,并构成模块名称的基础。 例如,测试套件可能包括

ext4_inode

ext4 子系统的一部分,测试 inode 区域。

kunit_try_catch

kunit 实现本身的一部分,测试 try_catch 区域。

apparmor_property_entry

apparmor 子系统的一部分,测试 property_entry 区域。

kasan

kasan 子系统只有一个套件,因此套件名称与子系统名称相同。

避免使用名称,例如

ext4_ext4_inode

没有理由两次声明子系统。

property_entry

如果没有子系统名称,则套件名称是不明确的。

kasan_integration_test

因为 kasan 子系统中只有一个套件,因此该套件应仅称为 kasan。 不要冗余地添加 integration_test。 它应该是一个单独的测试套件。 例如,如果添加单元测试,则该套件可以命名为 kasan_unittest 或类似名称。

测试用例

单个测试由一个测试约束代码路径、属性或函数的函数组成。 在测试输出中,单个测试的结果将显示为套件结果的子测试。

测试应以它们正在测试的内容命名。 这通常是被测函数的名称,并带有对正在测试的输入或代码路径的描述。 由于测试是 C 函数,因此应按照内核编码风格对其进行命名和编写。

注意

由于测试本身是函数,因此它们的名称不能与内核中的其他 C 标识符冲突。 这可能需要一些创造性的命名。 最好使您的测试函数为 static,以避免污染全局命名空间。

示例测试名称包括

unpack_u32_with_null_name

当传入 NULL 名称时测试 unpack_u32 函数。

test_list_splice

测试 list_splice 宏。 它具有前缀 test_ 以避免与宏本身发生名称冲突。

如果需要在其测试套件的上下文之外引用测试,则测试的完全限定名称应为套件名称后跟测试名称,并用冒号分隔(即 suite:test)。

测试 Kconfig 条目

每个测试套件都应绑定到一个 Kconfig 条目。

此 Kconfig 条目必须

  • 命名为 CONFIG_<name>_KUNIT_TEST:其中 <name> 是测试套件的名称。

  • 列在正在测试的驱动程序/子系统的配置条目旁边,或位于 [内核黑客] -> [内核测试和覆盖率] 下。

  • 依赖于 CONFIG_KUNIT

  • 仅在未启用 CONFIG_KUNIT_ALL_TESTS 时可见。

  • 默认值为 CONFIG_KUNIT_ALL_TESTS

  • 在帮助文本中简要描述 KUnit。

如果我们无法满足上述条件(例如,测试无法构建为模块),则测试的 Kconfig 条目应为三态。

例如,Kconfig 条目可能如下所示

config FOO_KUNIT_TEST
        tristate "KUnit test for foo" if !KUNIT_ALL_TESTS
        depends on KUNIT
        default KUNIT_ALL_TESTS
        help
          This builds unit tests for foo.

          For more information on KUnit and unit tests in general,
          please refer to the KUnit documentation in Documentation/dev-tools/kunit/.

          If unsure, say N.

测试文件和模块名称

KUnit 测试通常被编译成单独的模块。为了避免与常规模块冲突,KUnit 模块应该以测试套件的名称命名,后跟 _kunit(例如,如果核心模块是“foobar”,那么 KUnit 测试模块就是“foobar_kunit”)。

测试源文件,无论是编译成单独的模块还是在另一个源文件中 #include,最好都放在 tests/ 子目录中,以避免与其他源文件冲突(例如,用于制表符补全)。

请注意,_test 后缀也在一些现有的测试中使用。 建议使用 _kunit 后缀,因为它能更清晰地区分 KUnit 测试和非 KUnit 测试。

因此,对于常见的情况,将包含测试套件的文件命名为 tests/<suite>_kunit.ctests 目录应该与被测试的代码位于同一级别。 例如,lib/string.c 的测试位于 lib/tests/string_kunit.c 中。

如果套件名称包含测试父目录的部分或全部名称,则修改源文件名以减少冗余可能是合理的。 例如,一个 foo_firmware 套件可能位于 foo/tests/firmware_kunit.c 文件中。