一、简介
在汽车领域混了这么多年也做了不少项目,发现很多公司对软件单元测试和代码覆盖率测试根本不重视,或者开发流程就没有单元测试这个流程。但是有的客户需要评审单元测试这个流程,需要有相关的单元测试报告和代码覆盖率统计的报告。如果客户有这个要求就必须把这个开发流程重视起来,但是找了市面上很多工具并没有很满足要求的,既能实现单元测试又能顺便将代码的覆盖率统计出来。之前我写过一篇文章:温故而知新:gtest单元测试工具和lcov覆盖率统计工具的结合使用_gtest 覆盖率-CSDN博客 ,这篇文章主要介绍了如何将这两个工具结合起来作为单元测试工具。但是单元测试的过程中有的分支是没办法跑到的,比如需要依赖外部硬件的条件的情况下执行某个分支。例如有如下代码:
void control_flow(void)
{
int a = 10, b = 20;
stGPIO_Attrs gpio_attrs;
GPIO_Config(1, 0, gpio_attrs);
GPIO_OutLevel(1, 0, 0);
//gpio为高电平执行乘法运算否则执行加法运算
if(GPIO_GetPinLevel(1, 0) != 0) {
func_add(a, b);
}
else {
func_muti(a, b);
}
}
以上代码通过获取一个PIN脚的电平是高电平还是低电平执行不同的逻辑。但是单元测试工具一般是运行在windows环境下,硬件相关的代码是需要删除的。因此GPIO_GetPinLevel函数只能返回高电平或者低电平。因此在执行单元测试的时候只能跑一个分支,另一个分支无法被跑到。那么有没有办法让两个分支都跑到呢?答案是肯定的,那么就是对GPIO_GetPinLevel函数进行打桩。
二、函数打桩
函数打桩简单理解就是在实际运行代码的过程中用另一个函数的实现来替换实际函数的实现。比如上述GPIO_GetPinLevel函数就可以用下面的打桩函数来替换:
uint8_t GPIO_GetPinLevel_Stub(uint8_t gpio_port, uint8_t gpio_pin)
{
if(s_test_case == 0)
{
return 0;
}
else if(s_test_case == 1) {
return 1;
}
else {
return 2;
}
}
这样在程序运行的过程中就可以通过改变s_test_case变量的值来控制GPIO_GetPinLevel的返回值,从而获得高低电平。
三、该模版化工程的亮点
(1)基于gtest和lcov实现的既可以在实现单元测试的同时统计代码行覆盖率,并生成可视化报告。
(2)该工程提供了打桩功能可以方便用户在函数中制造各种异常case,人为制造在实际中跑不出来的情况。
(3)无论是单片机程序还是大型OS的程序都可以很简单的移植到该工程执行测试。
(4)生成的单元测试报告及覆盖率报告都是可视化的,该工程跑在ubuntu linux虚拟机上,环境搭建简单,移植方便,只需要将代码分别放在下图的Src和Inc目录下并编写测试用例即可运行。单元测试用例编写规则和gtest一致。
图1 单元测试工程模版主目录
图2 单元测试用例目录
图3 单元测试运行界面
图4 代码接口和行覆盖率统计结果
图5 单元测试结果报告
图6 单元测试用例编写用例
图7 具体接口覆盖率情况
注:有单元测试需要该模版的私信了解下