基本介绍
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 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);
}
标签:kunit,region,KUNIT,KUnit,ctx,test,EXPECT
From: https://www.cnblogs.com/alanli07/p/18399622