基本介绍
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/
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, ®ion_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 devicestruct 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);
}