使用CUnit进行单元测试的一些窍门
其实用CUnit进行单元测试很容易,因为C语言本身提供了宏替换这个强大的工具,可以很容易的实现非侵入式的测试。这里我们只讨论linux下使用gcc进行单元测试的情况,msvc不在讨论范围。
1.测试static的函数,static的语义是只有同一单元的代码才能访问static的函数或者变量,为了绕过这个限制,我们的测试 程序,需要直接
include待测试的CPP文件
#include "test.cpp"
2.比如C++类中有很多成员或者是private隔离级别的,测试时为了确认测试结果,很多时候需要调用这些函数,我们可以利用宏定义来绕过这些限制
#define protected public
#define private public
#include "test.cpp"
3. 比如有时我们想让标准函数fgets失败,来测异常情况,但是真正的失败有时很难做出来,那么我们就需要利用宏定义来替换指定的函数
#include <stdio.h>
static bool errflag = false;
static char *myfgets(char *s,int size,FILE *stream)
{
if(errflag)
{
return fgets(s,size,stream);
}
else
{
return NULL;
}
}
#undef fgets
#define fgets myfgets
#include "test.cpp"
用上面的方法我们就把标准库函数给替换了
4. 确认代码覆盖率和分支覆盖率
作为白盒测试的单元测试,我们的最低目标是代码100%,如果可能的话分支覆盖率也要达到100%, 我们在编译单元测试程序时,需要添加下面的编译选项
AM_CXXFLAGS=-O0 -fprofile-arcs -ftest-coverage
O0禁用所有优化,-fprofile-arcs -ftest-coverage用来编译代码覆盖率信息。
编译后,会在当前目录下生成*.gcno 文件,运行我们的测试程序后,会在当前目录下生成*.gcda文件,运行 gcov *.cpp就会生成很多的gcov文件,所有没有被覆盖的代码行会显示#####,我们只要搜索#####就可以知道那些代码还没测到。
要想知道分支覆盖率的话,只要执行gcov -b *.cpp命令就行,这时生成的gcov文件中会多出分支覆盖情况,我们只要搜索taken 0%的,一般就是没有被覆盖的分支。分支100%覆盖率是很难达到的,
if ( a || b)
xxxx
代码覆盖只要满足a 就可以,但是分支覆盖 需要 a, b, not a and not b 三个条件才行。
5.确认代码内存泄漏
除了分支覆盖率外,我们还需要保证代码没有内存泄漏,在linux提供了valgrind工具,可以用来检查内存,执行下面命令就可以了
valgrind --tool=memcheck --leak-check=full --leak-resolution=high --track-fds=yes ./test