EmbedC_TDD__1 Keil中搭建自动化单元测试框架Unity

1 什么是Unity

Unity是一个全部用C实现的自动化测试框架。它由很少的几个文件构成。

自动化测试框架就是一个软件包,它能让程序员表达产品代码应该有什么样的行为。自动化测试单元测试框架的工作需要提供以下能力:

  1. 用于表述测试用例的通用语言
  2. 用于表述期望结果的通用语言
  3. 能够使用产品代码所用的编程语言的功能
  4. 能够把所有的工程、系统或者子系统的单元测试用例收集到一起。
  5. 一个能运行全部或者部分测试用例的机制
  6. 对于测试套件的成功和失败给出明确的报告
  7. 对于失败的测试给出详细的报告

需要指出的是测试框架只是给我们实现了一套测试机制,具体的测试用例还需要我们自己编写。

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工程中

  1. 在工程文件中新建Unity目录,并拷贝从GitHub上下载下来的源码,如下图:
    在这里插入图片描述

  2. 在Keil已有的工程中新建Unity目录,用于和Unity相关的源码实现,然后加入unity.c和unity_fixture.c。如下图:
    在这里插入图片描述

  3. 包含新添加的头文件的路径
    在这里插入图片描述

  4. 在unity的源码examples中找到unity_config.h并放到我们工程的unity文件夹下。

  5. 编译已有的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机上进行。

发布了44 篇原创文章 · 获赞 60 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/u014421520/article/details/84025888