KUnit

官网

基本介绍

KUnit Suite Memory

每一个kUnit都有自己的上下文,所以一个崩溃了,不会影响到其他的suit。

开关

目前可以有下面几种方法控制case测试。

menuconfig控制
使用.kunitconfig控制编译的测试文件
使用宏选择性开启某些case
使用debugfs
kunit_get_current_test

总开关

CONFIG_KUNIT=y
CONFIG_KUNIT_DEFAULT_ENABLED=y

CONFIG_KUNIT: 将KUNIT框架编入内核。
CONFIG_KUNIT_DEFAULT_ENABLED:开启测试,如果是n会关闭测试。

测试文件开关

使用menuconfig

通过在Kconfig中配置测试文件的构建选项来控制是否加入测试。

例如,有Kunit测试文件 kunit-example-test.c , 可以通过在Kconfig中加入 CONFIG_KUNIT_EXAMPLE_TEST选项可以是y/m/n,并且在Makefile中添加:

obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += kunit-example-test.o

如果设置成m就会编译出.ko的驱动文件。在挂载的时候进行测试。

使用.kunitconfig

.kunitconfig是 a minconfig(通过运行生成的 .config ),用于运行一组特定的测试。如果想运行一组特定的测试,可以在.kunitconfig中提供Kconfig选项,以及所依赖的其他配置选项(架构配置、启动/禁用默写代码块配置、依赖项)。其根本也是使用Kconfig用来配置构建选项,具体可以见这里.

使用debugfs

可以通过配置 CONFIG_KUNIT_DEBUGFS=y ,开启Kunit提供的debugfs的功能。Kunit会在 /sys/kernel/debug/kunit// 下创建两个文件result和run。

cat results 就可以输出测试结果
echo anything > run 可以再次运行测试并输出测试结果

测试函数开关

使用宏来选择性开启case

可以在代码段中通过宏条件编译的方式选择性开启case。或者如果不想将测试的函数或者变量导出给测试文件使用,也可以使用下面的方法

static int do_interesting_thing(); #ifdef CONFIG_MY_KUNIT_TEST #include "my_kunit_test.c" #endif

kunit_get_current_test()

当需要用测试文件外部调用仅测试代码时,可以使用 kunit_get_current_test 。该函数可以通过task_struct中kunit_test来分析出当前的kunit上下文,并且如果Kunit没有启用,该函数返回null,也可以安全调用,并且对性能的影响忽略不计。所以可以通过这个特性,在待测函数中植入kunit测试,通过启用Kunit测试当做开关。例如:

#include <kunit/test-bug.h> /* for kunit_get_current_test */ struct test_data { int foo_result; int want_foo_called_with; }; static int fake_foo(int arg) { // 本函数从外部得到kunit上下文进行测试 struct kunit *test = kunit_get_current_test(); struct test_data *test_data = test->priv; KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg); return test_data->foo_result; } static void example_simple_test(struct kunit *test) { /* Assume priv (private, a member used to pass test data from * the init function) is allocated in the suite's .init */ struct test_data *test_data = test->priv; test_data->foo_result = 42; test_data->want_foo_called_with = 1; /* In a real test, we'd probably pass a pointer to fake_foo somewhere * like an ops struct, etc. instead of calling it directly. */ KUNIT_EXPECT_EQ(test, fake_foo(1), 42); }

使用kunit提供的一些状态函数

kunit_skip:跳过当前test

一些测试模板

最简测试模板

// 假测试函数 static void foo_test_fake(struct kunit *test) { const u32 array1[] = { 0x0F, 0xFF }; const u32 array2[] = { 0x1F, 0xFF }; /* Boolean assertions */ KUNIT_EXPECT_TRUE(test, true); KUNIT_EXPECT_FALSE(test, false); /* Integer assertions */ KUNIT_EXPECT_EQ(test, 1, 1); /* check == */ KUNIT_EXPECT_GE(test, 1, 1); /* check >= */ KUNIT_EXPECT_LE(test, 1, 1); /* check <= */ KUNIT_EXPECT_NE(test, 1, 0); /* check != */ KUNIT_EXPECT_GT(test, 1, 0); /* check > */ KUNIT_EXPECT_LT(test, 0, 1); /* check < */ /* Pointer assertions */ KUNIT_EXPECT_NOT_ERR_OR_NULL(test, test); KUNIT_EXPECT_PTR_EQ(test, NULL, NULL); KUNIT_EXPECT_PTR_NE(test, test, NULL); KUNIT_EXPECT_NULL(test, NULL); KUNIT_EXPECT_NOT_NULL(test, test); /* String assertions */ KUNIT_EXPECT_STREQ(test, "hi", "hi"); KUNIT_EXPECT_STRNEQ(test, "hi", "bye"); /* Memory block assertions */ KUNIT_EXPECT_MEMEQ(test, array1, array1, sizeof(array1)); KUNIT_EXPECT_MEMNEQ(test, array1, array2, sizeof(array1)); /* * There are also ASSERT variants of all of the above that abort test * execution if they fail. Useful for memory allocations, etc. */ KUNIT_ASSERT_GT(test, sizeof(char), 0); /* * There are also _MSG variants of all of the above that let you include * additional text on failure. */ KUNIT_EXPECT_GT_MSG(test, sizeof(int), 0, "Your ints are 0-bit?!"); KUNIT_ASSERT_GT_MSG(test, sizeof(int), 0, "Your ints are 0-bit?!"); } // 需要执行的cases static struct kunit_case sample_tests[] = { KUNIT_CASE(foo_test_fake), { /* sentinel */ } }; static struct kunit_suite sample_test_suite = { .name = "sample-test", .test_cases = sample_tests, }; kunit_test_suite(sample_test_suite);

driver需要fake device

可以使用 kunit_device_register 来创建一个fake device,当测试结束时会自动清理。同时在init中使用test→priv 传递device到各个cases中。

static void test_my_device(struct kunit *test) { struct device *fake_device; const char *dev_managed_string; // Create a fake device. fake_device = kunit_device_register(test, "my_device"); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_device) // Pass it to functions which need a device. dev_managed_string = devm_kstrdup(fake_device, "Hello, World!"); // Everything is cleaned up automatically when the test ends. } 在 linux-next/drivers/fpga/tests/fpga-region-test.c中有 static int fpga_region_test_init(struct kunit *test) { struct test_ctx *ctx; struct fpga_region_info region_info = { 0 }; ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); ctx->mgr_dev = kunit_device_register(test, "fpga-manager-test-dev"); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->mgr_dev); ctx->mgr = devm_fpga_mgr_register(ctx->mgr_dev, "Fake FPGA Manager", &fake_mgr_ops, &ctx->mgr_stats); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr)); ..... ctx->region = fpga_region_register_full(ctx->region_dev, &region_info); KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->region)); test->priv = ctx; return 0; } //cases中 static void fpga_region_test_class_find(struct kunit *test) { //使用传入的fake device struct test_ctx *ctx = test->priv; struct fpga_region *region; region = fpga_region_class_find(NULL, ctx->region_dev, fake_region_match); KUNIT_EXPECT_PTR_EQ(test, region, ctx->region); put_device(region->dev); }

从输出log信息中处理得到测试用例信息

Just set CONFIG_KUNIT=y CONFIG_KUNIT_DEBUGFS=y CONFIG_PINCTRL_MSM_TEST=y, then build the kernel image and flash it to device. During kernel boot process, will receive some information similar to the following.

[ 1.591001] KTAP version 1
[ 1.593870] 1..3
[ 1.597682] KTAP version 1
[ 1.600959] # Subtest: device-dts-test
[ 1.605408] # module: pinctrl_msm_test
[ 1.605428] 1..1
[ 1.622358] ok 1 get_correct_dts_test
[ 1.622390] ok 1 device-dts-test
[ 1.630229] KTAP version 1
[ 1.633413] # Subtest: pinmux_set_test
[ 1.637678] # module: pinctrl_msm_test
[ 1.637682] 1..2
[ 1.648330] ok 1 request_one_pin_test
[ 1.679433] ok 2 double_request_fail_test
[ 1.679528] # pinmux_set_test: pass:2 fail:0 skip:0 total:2
[ 1.684103] # Totals: pass:2 fail:0 skip:0 total:2
[ 1.689900] ok 2 pinmux_set_test
[ 1.698443] KTAP version 1
[ 1.701654] # Subtest: gpio_set_test
[ 1.705777] # module: pinctrl_msm_test
[ 1.705781] 1..1
[ 1.716401] ok 1 gpio_set_value_test
[ 1.716597] ok 3 gpio_set_test

Then, paste these messages into a file and use the KUnit tool to parse them.
./tools/testing/kunit/kunit.py parse <message file>
We can obtain the output as follows.
[21:30:57] ============================================================
[21:30:57] ============== device-dts-test (1 subtest) ===============
[21:30:57] [PASSED] get_correct_dts_test
[21:30:57] ================ [PASSED] device-dts-test ================
[21:30:57] =============== pinmux_set_test (2 subtests) ===============
[21:30:57] [PASSED] request_one_pin_test
[21:30:57] [PASSED] double_request_fail_test
[21:30:57] ================= [PASSED] pinmux_set_test =================
[21:30:57] ================ gpio_set_test (1 subtest) =================
[21:30:57] [PASSED] gpio_set_value_test
[21:30:57] ================== [PASSED] gpio_set_test ==================
[21:30:57] ============================================================
[21:30:57] Testing complete. Ran 4 tests: passed: 4

Due to CONFIG_KUNIT_DEBUGFS=y, we can also find two files, /sys/kernel/debug/kunit/<suite>/results and /sys/kernel/debug/kunit/<suite>/run. Running cat /sys/kernel/debug/kunit/<suite>/results will display the output.


__EOF__

本文作者alan
本文链接https://www.cnblogs.com/alanli07/p/18399622.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   LIalan  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
点击右上角即可分享
微信分享提示