前面我们写过一篇关于Kunit怎么快速使用起来的文章,但是当时只是搭建了框架,让整个KUNIT跑起来了。使用到的关于KUNIT中的东西还是比较的少。现在这次我们去测试一些复杂的场景,使用到一些复杂的断言。继续我们的二点点KUNIT,学习一下KUNIT中的东西。

1、测试用例

在KUNIT中最基本的单元就是测试用例,一个测试用例就是一个函数:void (*)(struct kunit *test)。在这个函数下面调用了需要测试的接口。比如:

void example_test_success(struct kunit *test)
{
}

void example_test_failure(struct kunit *test)
{
        KUNIT_FAIL(test, "This test never passes.");
}

在上面的代码中,example_test_success 始终会通过,因为这个函数实际上什么都没做。而下面的example_test_failure始终会失败,因为这个调用了KUNIT_FAIL这个特殊的断言,这个会打印失败信息,并让这个用例测试不通过。

2、期望-KUNIT_EXPECT_EQ

这个期望就是指我们期望一段代码的运行结果应该是什么样子的。这个期望被称为函数。测试是通过设置对被测试代码行为的期望来进行的。

当一个或多个预期失败时,测试函数的结果与我期望的不相符合的时候,测试用例失败,并记录有关失败的信息。例如:

void add_test_basic(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, 1, add(1, 0));
        KUNIT_EXPECT_EQ(test, 2, add(1, 1));
}

在上面的示例中,add_test_basic对一个名为add的函数的行为进行了许多断言。第一个参数始终是struct kunit*类型其中包含有关当前测试上下文的信息。

在本例中,第二个参数是期望的值。最后一个值是实际值。如果add通过了所有这些期望,测试用例add_test_basic将通过;如果这些期望中的任何一个失败,测试用例将失败。

当违反任何期望时,测试用例失败;然而,测试将继续运行,并尝试其他预期,直到测试用例结束或终止。这与稍后讨论的断言相反。

关于kunit的二点够用就行知识概念-LMLPHP
例如,如果我们想要严格测试上面的add函数,请创建额外的测试用例,测试add函数应该具有的每个属性,如下所示:

{
        KUNIT_EXPECT_EQ(test, 1, add(1, 0));
        KUNIT_EXPECT_EQ(test, 2, add(1, 1));
}

void add_test_negative(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, 0, add(-1, 1));
}

void add_test_max(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX));
        KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN));
}

void add_test_overflow(struct kunit *test)
{
        KUNIT_EXPECT_EQ(test, INT_MIN, add(INT_MAX, 1));
}

就是要让测试用例越简单越好。

3、断言-Assertions

断言类似于预期,只是如果条件不满足,断言会立即终止测试用例。例如:

static void test_sort(struct kunit *test)
{
        int *a, i, r = 1;
        a = kunit_kmalloc_array(test, TEST_LEN, sizeof(*a), GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, a);
        for (i = 0; i < TEST_LEN; i++) {
                r = (r * 725861) % 6599;
                a[i] = r;
        }
        sort(a, TEST_LEN, sizeof(*a), cmpint, NULL);
        for (i = 0; i < TEST_LEN-1; i++)
                KUNIT_EXPECT_LE(test, a[i], a[i + 1]);
}

在这个例子中,被测试的方法应该返回一个值的指针。如果指针返回null或errno,我们希望停止测试,因为以下预期可能会导致测试用例崩溃。**ASSERT_NOT_ERR_OR_NULL(…)**允许我们在不满足完成测试的适当条件时退出测试用例。(见名知意)

4、测试套件

我们需要很多测试用例来覆盖单元的所有行为。有很多类似的测试是很常见的。为了减少这些密切相关的测试中的重复,大多数单元测试框架(包括KUnit)都提供了测试套件的概念

测试套件是一个代码单元的测试用例集合,具有可选的设置和拆卸功能,在整个套件和/或每个测试用例之前/之后运行。例如:

static struct kunit_case example_test_cases[] = {
        KUNIT_CASE(example_test_foo),
        KUNIT_CASE(example_test_bar),
        KUNIT_CASE(example_test_baz),
        {}
};

static struct kunit_suite example_test_suite = {
        .name = "example",
        .init = example_test_init,
        .exit = example_test_exit,
        .suite_init = example_suite_init,
        .suite_exit = example_suite_exit,
        .test_cases = example_test_cases,
};
kunit_test_suite(example_test_suite);

在上面的示例中,测试套件example_test_suite将首先运行example_suite_init,然后运行测试用例example_test_foo、example_test_bar和example_test_baz。每个函数都会在其前面立即调用example_test_init并在其后面立即调用example_test_exit。最后,example_suite_exit将在所有其他操作之后调用。kunit_test_suite(example_test_ssuite)向kunit测试框架注册测试套件。

这个就是通过这个测试套件,将一些需要初始化和退出的测试用例,给准备了环境。

关于kunit的二点够用就行知识概念-LMLPHP
测试用例只有在与测试套件关联时才会运行。kunit_test_suite(…)是一个宏,它告诉链接器将指定的测试套件放在一个特殊的链接器部分中,以便kunit可以在late_init之后运行,或者在加载测试模块时运行(如果测试是作为模块构建的)。

12-08 09:04