在嵌入式领域,尤其是MCU领域,一般很少有使用单元测试框架,一般就是开发阶段开发人员按照自己的习惯和经验进行自测,然后就是系统集成测试,所以一般在单元测试这一环做的不是很规范。实际上我们在开发中应该要改善这种现状,加强单元测试的管理,避免单元测试纯凭开发人员是否有时间做,做到什么程度也是随缘。应该由测试来保证开发质量,避免依赖于个人,并且积累测试用例库,这样有助于产品迭代稳定,尤其是在BSP等领域,有一个好的测试框架和测试用例集能很好的完成芯片的验证,和生产测试等工作。
恰好有这样一个框架,专为嵌入式领域纯粹的C测试而生-unity,使用ANSI C编写,移植性好,资源占用少,就一个C文件和h文件,可以通过h进行一些配置,特别适合MCU开发等领域。
http://www.throwtheswitch.org/
http://www.throwtheswitch.org/unity
https://github.com/ThrowTheSwitch/Unity/
或者
https://github.com/ThrowTheSwitch/Unity/archive/master.zip
http://www.throwtheswitch.org/unity
这个页面可以看到基本的介绍,浏览一下就知道个大概了,
https://github.com/ThrowTheSwitch/Unity/
下的README.md也可以先看一下。
先不管细节,不需要了解很多,不管三七二十一先用了再说。
这里使用某个MCU的开发板,MDK环境进行测试。
我们这里使用源码中的example_1进行测试。
将下载的源码Unity\\src下的unity.c,unity.h,unity_internals.h
Unity\\examples下的unity_config.h
放到自己工程的unity目录下,这一部分是unity源码
Unity\\examples\\example_1\\src下的所有文件放置到自己工程的src目录下,这一部分是用户代码需要测试的
Unity\\examples\\example_1\\test下的所有文件放置到自己工程的test目录下,这一部分是测试代码
添加上述几个文件夹到头文件包含路径
默认依赖打印输出函数putchar
见unity_internals.h中
#ifndef UNITY_OUTPUT_CHAR
/* Default to using putchar, which is defined in stdio.h */
#include < stdio.h >
#define UNITY_OUTPUT_CHAR(a) (void)putchar(a)
#else
/* If defined as something else, make sure we declare it here so it's ready for use */
#ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION
extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION;
#endif
#endif
我们要根据自己的情况进行移植,
unity_config.h中配置以下宏,其中RS232_putc在我们自己的代码中实现
注意:需要在unity_internals.h中#define UNITY_INCLUDE_CONFIG_H 1
或者在工程配置中定义宏UNITY_INCLUDE_CONFIG_H,才会使用unity_config.h
比如MDK工程中设置
如果已经实现了标准输入输出重定向,有putchar则不需要使能这些宏,直接使用putchar。
example_1中有两个测试,一个是源码带2的一个是不带2的。
代码中
先将带2的相关代码不进行编译
将TestProductionCode_Runner.c中的main函数名改为testrunner_main
在自己工程的main函数中调用该函数(先 extern int testrunner_main(void);申明下函数)
运行程序打印如下
test/TestProductionCode.c:20:test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode:PASS
test/TestProductionCode.c:33:test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken:FAIL: Expected 1 Was 0
test/TestProductionCode.c:41:test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue:PASS
test/TestProductionCode.c:51:test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain:PASS
test/TestProductionCode.c:61:test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed:FAIL: Expected 0x00001234 Was 0x00005A5A
-----------------------
5 Tests 2 Failures 0 Ignored
FAIL
使用带2的代码
TestProductionCode2_Runner.c中main函数名改为testrunner2_main
在自己的代码中调用
testrunner2_main
先 extern int testrunner2_main(void);申明该函数
运行看到输出如下
test/TestProductionCode2.c:20:test_IgnoredTest:IGNORE: This Test Was Ignored On Purpose
test/TestProductionCode2.c:25:test_AnotherIgnoredTest:IGNORE: These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet
test/TestProductionCode2.c:30:test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented:IGNORE
-----------------------
3 Tests 0 Failures 3 Ignored
OK
以上可以看到,unnity进行单元测试十分方便,移植也很简单,先进行一个初体验,后面再详细介绍其使用和设计原理。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !