Unity是一个单元测试框架。我们的目标是保持它的规模和功能。核心的Unity测试框架有三个文件:一个C文件和两个头文件。它们共同提供函数和宏,使测试更容易。
测试文件是C文件。通常情况下,将为要测试的每个C模块创建一个测试文件。测试文件应该包括unity.h和要测试的C模块的头文件。接下来,测试文件将包括setUp()和tearDown()函数。
setUp函数可以包含希望在每次测试之前运行的任何内容。
tearDown函数可以包含希望在每次测试之后运行的任何内容。
这两个函数都不接受参数,也不返回任何东西。如果你不需要它们,你可以把它们中的一个或两个都留空。
文件的大部分将是一系列测试函数。测试函数遵循以 test_ 或 spec_ 开头的惯例。您不必这样命名它们,但是它清楚地说明了哪些函数是针对其他开发人员的测试。此外,与Unity或Ceedling一起提供的自动化脚本将默认寻找以这种方式添加前缀的测试函数。测试函数不接受任何参数,也不返回任何结果。所有的测试会计都在Unity内部处理。
最后,在测试文件的底部,将编写一个main()函数。这个函数将调用UNITY_BEGIN(),然后为每个测试调用RUN_TEST,最后调用UNITY_END()。这实际上会触发每个测试函数运行,因此每个函数都有自己的RUN_TEST调用是很重要的。
完成后,测试文件将如下所示:
1. #include "unity.h"
2. #include "file_to_test.h"
3.
4. void setUp(void) {
5. // set stuff up here
6. }
7.
8. void tearDown(void) {
9. // clean stuff up here
10. }
11.
12. void test_function_should_doBlahAndBlah(void) {
13. //test stuff
14. }
15.
16. void test_function_should_doAlsoDoBlah(void) {
17. //more test stuff
18. }
19.
20. // not needed when using generate_test_runner.rb
21. int main(void) {
22. UNITY_BEGIN();
23. RUN_TEST(test_function_should_doBlahAndBlah);
24. RUN_TEST(test_function_should_doAlsoDoBlah);
25. return UNITY_END();
26. }
(1)先写一个简单的接口powerCode16To8,作用是指定偏移量,将一串16位的通信码转换成8位的通信码:
1. /**************************************************************************
2. * 函数名称:powerCode16To8
3. * 功能描述:电源板16位通信码转8位通信码
4. * 输入参数:
5. * 输出参数:
6. * 返 回 值:
7. * 其它说明:
8. **************************************************************************/
9. int powerCode16To8(IN int offset, IN uint8_t p_power_code_16[COMM_CODE_TOTAL_LEN], OUT uint8_t p_power_code_8[COMM_CODE_LEN])
10. {
11. int i;
12. memset(p_power_code_8,0x00,sizeof(COMM_CODE_LEN));
13. for(i = 0;i < COMM_CODE_LEN;i ++)
14. {
15. p_power_code_8[i] = p_power_code_16[offset + i];
16. }
17.
18. return 1;
19. }
(2)编写测试用例如下,该用例将一个16位的通信码,向右偏移一位,取其前八位作为结果power_code_8,与预期结果t_power_code_8进行比较,如果比较结果一致,则视为用例通过:
1. void Test_Motor_Given_power_code_16_When_powerCode16To8_Then_OK(void)
2. {
3. uint8_t power_code_16[COMM_CODE_TOTAL_LEN] =
4. {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
5. 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
6. uint8_t power_code_8[COMM_CODE_LEN] = {0};
7. uint8_t t_power_code_8[COMM_CODE_LEN] =
8. {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
9.
10. powerCode16To8(1, power_code_16, power_code_8);
11. TEST_ASSERT_EQUAL_HEX8_ARRAY(t_power_code_8, power_code_8, COMM_CODE_LEN);
12. }
(3)编写RUN_TEST,并在main函数中加入测试用例(可以用宏控制测试版本和非测试版本,以控制片上资源的消耗)
1. void Test_Motor_Entry()
2. {
3. SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
4. printf("\r\n%s\t\t%s\r\n", __DATE__, __TIME__);
5.
6. UNITY_BEGIN();
7. RUN_TEST(Test_Motor_Given_power_code_16_When_powerCode16To8_Then_OK);
8. UNITY_END();
9. }
10.
11. int main(void)
12. {
13. /****************单元测试模块****************/
14. #ifdef UNITY_TEST_ASSERT
15.
16. Test_Motor_Entry();
17.
18. #endif
19. /********************END********************/
20. }
(4)编译运行并通过SEGGER_RTT(先在Project.map里面找到_SEGGER_RTT的地址(内部flash的地址),再在打开的RTT_Viewer中输入对应的地址,就可以输出Unity输出的打印信息),可以打印测试结果如下(也可以通过Telnet本机127.0.0.1的方式,将打印的内容输出到SecureCRT等工具中,拷贝出来分析):
【1】《C语言单元测试Unity使用(一) 入门指南》
【2】《Keil中搭建自动化单元测试框架Unity》
【3】GitHub中Unity开源库文件