0%

自动化单元测试框架说明

上一篇文章中,简单介绍了什么是测试驱动开发的开发模式。俗话说得好,工欲善其事,必先利其器。有了开发模式的思路,就要准备好开发的工具了。

下面就先来介绍一下自动化单元测试框架

什么是自动化单元测试框架?

自动化单元测试框架本质上就是一个软件包,目的是让我们能够确保我们编写的代码符合我们的设计预期,自动对我们编写的代码进行输入/输出,然后对比期望结果,最后输出测试报告。

在其他的编程语言中,有很多成熟的自动化单元测试框架,例如:CppUnity。为了符合嵌入式C语言开发的目的,下面简单介绍两个自动化单元测试框架: Unity 和 cutest 。

Unity: 一个全部用 C 实现的自动化测试框架

Unity 自动化单元测试框架是《测试驱动的嵌入式C语言开发》作者开发的一个全部用 C 实现的自动化测试框架,在 github 上能够找到代码仓库(https://github.com/ThrowTheSwitch/Unity)。

下面给出这个框架在使用时的一个例子用于说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "unity_fixture.h"

TEST_GROUP(sprintf);

static char output[100];
static const char *expected;

TEST_SETUP(sprintf)
{
memset(output, 0xaa, sizeof output);
expected = "";
}

TEST_TEAR_DOWN(sprintf)
{
}

static void expect(const char *s)
{
expected = s;
}

static void given(int charsWriten)
{
TEST_ASSERT_EQUAL(strlen(expected), charsWriten);
TEST_ASSERT_EQUAL_STRING(expected, output);
TEST_ASSERT_BYTES_EQUAL(0xaa, output[strlen(expected) + 1]);
}

TEST(sprintf, NoFormatOperations)
{
expect("hey");
given(sprintf(output, "hey"));
}

TEST(sprintf, InsertString)
{
expect("Hello World\n");
given(sprintf(output, "Hello %s\n", "World"));
}

TEST_GROUP_RUNNER(sprintf)
{
RUN_TEST_CASE(sprintf, NoFormatOperations);
RUN_TEST_CASE(sprintf, InsertString);
}

static void RunAllTests(void)
{
RUN_TEST_GROUP(sprintf);
}

int main(int argc, char *argv[])
{
return UnityMain(argc, argv, RunnAllTests);
}

以上的例子说最简单的 Unity 框架的使用说明。

TEST_SETUP 函数的主要功能是在每个单元测试开始前,完成对环境的配置,确保每个测试用例的运行条件。

TEST_TEAR_DOWN 函数的主要功能是在每个单元测试运行结束后,恢复整体的运行环境,确保单元测试运行后不会对其他的测试组造成影响。

TEST_SETUPTEST_TEAR_DOWN 被称为测试夹具

TEST 宏是用于定义测试用例的,每个测试用例尽量做到功能单一、明确。测试用例的选择以及策略有专门的软件测试的书籍进行介绍,我就不再进一步进行说明。

TEST_GROUP_RUNNER 是将需要进行的单元测试注册到测试组中。

RunAllTests 确定了需要执行的测试组,在使用时可以结合自己的实际来使用。

cutest

cutest(https://github.com/asimjalis/cutest) 是我在 github 上找到的另外一个全部由 C 实现的自动化测试框架。所有的实现代码只有 CuTest.hCuTest.c 两个文件,可以很好的嵌入到任何的工程中进行使用。

在 cutest 的工程中的 README.MD 文件中给出了 cutest 使用的示例。

测试用例文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "CuTest.h"

char* StrToUpper(char* str) {
return str;
}

void TestStrToUpper(CuTest *tc) {
char* input = strdup("hello world");
char* actual = StrToUpper(input);
char* expected = "HELLO WORLD";
CuAssertStrEquals(tc, expected, actual);
}

CuSuite* StrUtilGetSuite() {
CuSuite* suite = CuSuiteNew();
SUITE_ADD_TEST(suite, TestStrToUpper);
return suite;
}

测试运行文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "CuTest.h"

CuSuite* StrUtilGetSuite();

void RunAllTests(void) {
CuString *output = CuStringNew();
CuSuite* suite = CuSuiteNew();

CuSuiteAddSuite(suite, StrUtilGetSuite());

CuSuiteRun(suite);
CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output);
printf("%s\n", output->buffer);
}

int main(void) {
RunAllTests();
}

针对 cutest 的使用就不再进一步进行说明了,详细的可以查看 cutest 工程的具体内容。

“四阶段”模式

最后,在对测试中的“四阶段”模式进行一下简单的说明。其实“四阶段”模式,只是将单元测试分为了 4 个阶段进行来划分,建立的行为模型而已。主要包括:

  • 建立:创建测试的前置条件。
  • 运行:对系统进行操作。
  • 验证:检查预期的输出。
  • 拆卸:把被测系统恢复到测试前的初始状态。

PS:牢记这四个阶段,就可以把单元测试的整个过程掌握了。