系统调用测试框架基于kunit的单元测试与验证 - 第4节

4.1 内核源码获取与版本选择

搭建 KUnit 测试环境的第一步是获取合适的内核源码。KUnit 自 Linux 内核 4.15 版本起以实验性功能引入,并在 5.0 版本后趋于稳定。建议使用长期支持(LTS)版本或最新的稳定主线内核,以获得最完整的 KUnit 支持。

版本建议:推荐使用 Linux 5.15 LTS 或更高版本。如果使用 4.15 ~ 4.20 之间的内核,部分 KUnit 宏和断言可能不可用,需要手动向后移植。

4.1.1 获取内核源码的三种方式

方式 命令/操作 适用场景
Git 克隆主线仓库 git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 开发最新特性、贡献补丁
下载 LTS 源码包 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.xx.tar.xz 稳定测试、产品级验证
发行版源码包 apt-get source linux-image-$(uname -r) 快速适配当前系统环境

获取源码后,进入内核根目录:

cd linux
git checkout v5.15  # 如果使用 Git 克隆,切换到指定标签
内核源码获取流程 Git 克隆主线 torvalds/linux.git 下载 LTS 源码包 kernel.org 稳定版本 发行版源码包 apt-get source 进入内核根目录 配置 KUnit 选项

4.2 KUnit 配置选项详解

KUnit 的配置选项位于内核配置菜单的 Kernel hacking 子菜单下。正确配置这些选项是编译和运行 KUnit 测试模块的前提。

4.2.1 核心配置选项

配置宏 说明 推荐值
CONFIG_KUNIT KUnit 框架核心支持,启用测试基础设施 y 或 m
CONFIG_KUNIT_TEST KUnit 框架自身的自测试用例 m(模块方式)
CONFIG_KUNIT_EXAMPLE_TEST KUnit 示例测试模块,用于验证环境 m
CONFIG_KUNIT_ALL_TESTS 启用所有 KUnit 测试(谨慎使用) n

4.2.2 配置操作步骤

  1. 进入配置界面:在内核根目录执行 make menuconfig(需要 ncurses 库)。
  2. 导航路径:进入 Kernel hacking → KUnit 子菜单。
  3. 启用核心支持:将 KUnit support 设置为 y(编译进内核)或 m(编译为模块)。
  4. 启用示例测试:将 KUnit example test 设置为 m,用于后续验证。
  5. 保存退出:保存配置并退出 menuconfig。
注意:如果使用 make defconfig 生成默认配置,KUnit 选项默认是关闭的。必须手动通过 make menuconfig 或直接编辑 .config 文件来启用。

4.2.3 直接编辑 .config 文件

对于自动化脚本或批量构建场景,可以直接修改 .config 文件:

# 确保以下行存在于 .config 文件中
CONFIG_KUNIT=y
CONFIG_KUNIT_TEST=m
CONFIG_KUNIT_EXAMPLE_TEST=m
# 如果不需要全部测试,确保以下行被注释或设为 n
# CONFIG_KUNIT_ALL_TESTS is not set
KUnit 配置选项依赖关系 CONFIG_KUNIT (核心框架) CONFIG_KUNIT_TEST CONFIG_KUNIT_EXAMPLE_TEST CONFIG_KUNIT_ALL_TESTS 配置依赖说明 • CONFIG_KUNIT 是基础开关,其他选项依赖它 • CONFIG_KUNIT_ALL_TESTS 会启用所有测试,可能导致内核膨胀 • 建议先启用 CONFIG_KUNIT_EXAMPLE_TEST 验证环境

4.3 编译 KUnit 测试模块

配置完成后,进入编译阶段。KUnit 测试模块可以编译为内核模块(.ko 文件),也可以直接编译进内核镜像。推荐以模块方式编译,便于加载和卸载。

4.3.1 编译命令

# 编译内核和模块(包含 KUnit 测试模块)
make -j$(nproc)

# 如果只需要编译模块,不重新编译整个内核
make modules -j$(nproc)

# 只编译特定 KUnit 模块(以 example-test 为例)
make M=lib/kunit/tests/ -j$(nproc)

4.3.2 编译产物验证

编译完成后,检查生成的模块文件:

# 查找 KUnit 相关模块
find . -name "*.ko" | grep kunit

# 典型输出示例
./lib/kunit/kunit.ko
./lib/kunit/kunit-test.ko
./lib/kunit/kunit-example-test.ko

4.3.3 常见编译错误及解决

错误信息 原因 解决方案
undefined reference to 'kunit_test_suites' KUnit 核心未编译或未链接 确认 CONFIG_KUNIT=y 已生效
implicit declaration of function 'kunit_assert' 内核版本过低,KUnit API 不完整 升级内核至 5.0+ 或向后移植头文件
KUnit example test not found in modules.order 配置未正确保存或 make 未重新读取 执行 make olddefconfig 后重新编译
调试技巧:如果编译失败,先检查 .config 文件中 KUnit 相关配置是否确实被设置为 y 或 m。有时 make menuconfig 的依赖解析会静默关闭某些选项。使用 grep CONFIG_KUNIT .config 快速确认。

4.4 加载与运行 KUnit 测试模块

编译成功后,将模块加载到运行中的内核进行测试。

4.4.1 模块加载命令

# 加载 KUnit 核心模块(如果编译为模块)
sudo insmod lib/kunit/kunit.ko

# 加载示例测试模块
sudo insmod lib/kunit/kunit-example-test.ko

# 查看内核日志输出
dmesg | tail -50

4.4.2 预期输出示例

成功加载后,dmesg 中应包含类似以下内容:

[ 1234.567890] TAP version 14
[ 1234.567891] 1..1
[ 1234.567892]     # Subtest: example
[ 1234.567893]     1..1
[ 1234.567894]     ok 1 - example_simple_test
[ 1234.567895] ok 1 - example

4.4.3 卸载模块

# 卸载测试模块
sudo rmmod kunit-example-test
sudo rmmod kunit  # 如果核心模块不再需要
KUnit 测试模块生命周期 编译模块 insmod 加载 执行测试 rmmod 关键输出位置 • 测试结果通过内核日志(dmesg)输出,格式为 TAP(Test Anything Protocol) • 每个测试套件输出 "ok n - test_name" 表示通过,"not ok" 表示失败 • 可以使用 dmesg -w 实时查看测试输出

4.5 环境验证清单

完成上述步骤后,使用以下清单确认环境搭建成功:

检查项 验证方法 预期结果
内核源码完整性 ls arch/x86/ 检查架构目录 目录存在且包含 Kconfig 文件
KUnit 配置生效 grep CONFIG_KUNIT .config 输出 CONFIG_KUNIT=y 或 =m
模块编译成功 find . -name "kunit-example-test.ko" 文件存在且非空
测试执行通过 dmesg | grep "ok 1 - example" 输出包含测试通过信息
快速验证脚本:可以将以下命令保存为 check_kunit_env.sh,一键验证环境:
#!/bin/bash
echo "=== KUnit 环境检查 ==="
grep CONFIG_KUNIT .config && echo "[OK] KUnit 已配置" || echo "[FAIL] KUnit 未配置"
find . -name "kunit-example-test.ko" | grep -q . && echo "[OK] 测试模块已编译" || echo "[FAIL] 测试模块未编译"
echo "=== 检查完成 ==="