1 什么是Unity
Unity是一个全部用C实现的自动化测试框架。它由很少的几个文件构成。
自动化测试框架就是一个软件包,它能让程序员表达产品代码应该有什么样的行为。自动化测试单元测试框架的工作需要提供以下能力:
- 用于表述测试用例的通用语言
- 用于表述期望结果的通用语言
- 能够使用产品代码所用的编程语言的功能
- 能够把所有的工程、系统或者子系统的单元测试用例收集到一起。
- 一个能运行全部或者部分测试用例的机制
- 对于测试套件的成功和失败给出明确的报告
- 对于失败的测试给出详细的报告
需要指出的是测试框架只是给我们实现了一套测试机制,具体的测试用例还需要我们自己编写。
2 为什么要使用Unity
使用Unity的好处将在另一篇博文中详细介绍。请点击这里查看。
3 获取Unity的源码
两种途径可以获取到源码
unity官网 http://www.throwtheswitch.org/unity
github https://github.com/ThrowTheSwitch/Unity
4 Unity源码目录结构分析
目录 | 内容 |
---|---|
src | 这个文件夹中包含unity.c、unity.h、unity_internals.h,这是最基本的Unity组成,有了这三个文件你就可以开始编写测试用例了 |
docs | Untiy的相关应用文档都在这里,有条件同学建议都读一下 |
auto | 简化测试用例搭建的Ruby脚本,没研究过Ruby,暂时不知道咋用 |
examples | 参考测试例程 |
extras | 附加实现夹具的功能 |
test | Unity的所有的测试 |
5 在Keil中搭建Unity
5.1 将Unity源码添加到Kiel工程中
-
在工程文件中新建Unity目录,并拷贝从GitHub上下载下来的源码,如下图:
-
在Keil已有的工程中新建Unity目录,用于和Unity相关的源码实现,然后加入unity.c和unity_fixture.c。如下图:
-
包含新添加的头文件的路径
-
在unity的源码examples中找到unity_config.h并放到我们工程的unity文件夹下。
-
编译已有的keil工程,无错误无警告后继续,有错误则检测。
5.2 配置unity_config.h
打开unity_config.h并配置,主要是为了配置一些数据类型和打印的重定向。我使用cm4内核定义的配置如下:
#define UNITY_EXCLUDE_LIMITS_H /* 调用limits.h, UINT_MAX和ULONG_MAX默认是32位*/
#define UNITY_EXCLUDE_STDINT_H /* */
#define UNITY_INT_WIDTH 32 /* int型变量是32位 */
#define UNITY_POINTER_WIDTH 32 /* 设置指针为32位 因为我们是32位系统 */
#define UNITY_INCLUDE_DOUBLE /**/
#define UNITY_OUTPUT_CHAR(a) fputc(a, stdout) /* 重定向输出打印函数 */
#define UNITY_SUPPORT_WEAK __attribute__((weak)) /* 设置Unity中setup、teardown、suiteSetUp、suiteTearDown为弱函数如,果自己的工程中有setup函数Unity中自动无效而不会产生重定义问题。具体以源码中介绍为准。*/
其中比较重要的配置就是unity输出的重定向了,这个函数会打印具体的unity的输出信息,如果我们现有的工程是使用串口输出,则可以直接定向到串口输出上,这里我使用的是EventRecoder调试工具,使用标准的printf输出,所以直接重定向到了fputc上。
5.3 编写测试用例
完成以上的步骤,我们就可以使用Unity了。仿照examples里的例子,我们直接创建一个TestProductionCode_Runner.c文件,该文件包含了Unity的入口main函数。所以,对于我们工程的main函数来说,就不能这么写了,在完成相关的初始化后,必须退出,然后进入到Unity的main函数入口。改动如下:
#ifdef USING_UNITY_MAIN
int product_main(void)
#else
int main(void)
#endif
{
EventRecorderInitialize(EventRecordAll, 1U);
EventRecorderStart();
delay_init(168); //初始化延时函数
LED_Init(); //初始化LED端口
OLED_Init(); //初始化OLED
OLED_Clear();
OLED_ShowString(0,0,"0.96' OLED TEST",16);
printf("Hello EventRecord!\r\n");
#ifndef USING_UNITY_MAIN
while(1)
{
LED2 = 0;
LED3 = 1;
delay_ms(500);
LED2 = 1;
LED3 = 0;
delay_ms(500);
}
#endif
return 0;
}
5.3 Unity测试结果解析
如上所示,没有消息就是最好的消息,如果全部测试通过,最后会打印OK,如果测试失败,则会反馈失败的原因和具体的失败位置。
最后,工程源码请点击这里获取。
最后的最后,如果使用目标处理器编译运行Unity是会消耗目标MCU的资源的,所以在嵌入式软件开发中,Unity的测试应该在PC机上进行。