版权声明:本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名elloop(包含链接)
#前言
本文介绍了如何使用宏来控制C++单元测试的开启和关闭,本文的单元测试工具指的是google的C++测试框架gtest。
gtest目前最新的稳定release版本是1.7,关于gtest的介绍请移步gtest的主页,它的编译安装和使用都很简单,你可以直接把gtest的源码copy到自己项目里来使用,也可以使用header+静态库的方式集成到项目中。入门的话建议从它源码仓库里自带的测试用例看起,模仿着这些sample写用例可以快速上手。本文不对具体使用方法做介绍。
当单元测试变多的时候遇到的麻烦
我对gtest使用比较多的特性是基本的TEST
测试,典型的用法像下面的代码这样:
测试代码中,我定义了一个测试用例,包含三个子测试Test123,其中输出那么多行的i是为了模拟测试用例可能的复杂输出,上面的测试结果如下:
Test1, Test2通过,Test3中1 > i的条件失败,导致其未通过。
遇到的麻烦
从结果中可以看到,仅仅三个子测试就已经可能有这么多输出了,当我添加更多的文件,每个文件里有更多的测试用例的时候麻烦就出现了,我要从好几页的输出结果中,找到某个特定的测试用例的输出可是要看好一会呢。
解决问题
解决这个麻烦,我的需求是:
每次运行程序时,只显示我要测试的用例,这样测试结果就一目了然了。
方案1:把其它测试删掉或注释掉?
不行,不能删除用例,因为好些用例是很有价值的,包括正在学习的类库用法什么的要保留下来以后复习。注释掉太麻烦了,写的用例越来越多,一个个注释很麻烦,以后想再运行某个用例的时候还有再解注释,麻烦。
方案2:修改gtest源码,给TEST加上附加参数来控制某个TEST要不要运行
不行,这样搞代价太大而且有些有力过猛的感觉,以后gtest升级的话会受影响。
方案3:弄一个全局开关,在每个TEST体内,根据开关状态判断,如果开关打开,那就直接返回,不输出。
在需要输出的用例中,不加条件判断,在测试完毕之后再加上条件。这样只有每次新加的测试会有输出。当想打开所有测试的时候,把全局的开关打开就行了。看起来不错,但是运行起来的时候会发现,虽然那些用例没有输出但是gtest还是会打印出那些测试用例的测试报告,即使它是个没有任何测试条件和输出的用例。
因此,要想不让其它不需要运行的测试干扰我的视线,最根本的办法应该是在编译层面来做控制,因为只要TEST()一旦被编译,这个测试用例就会在最终的输出中出现。
控制编译过程?那就要靠宏了,虽然它的名声不咋地。
最终方案:使用宏来控制编译过程,过滤掉不需要运行的TEST
思路:
1. 使用RUN_GTEST
和BEGIN_TEST
来代替TEST来定义测试用例 (“通过简单地增加另外一个间接层就可以解决软件的任何问题”)
2. 使用RUN_GTEST
定义的用例是在本次编译后,肯定会被执行的用例
3. 使用BEGIN_TEST
定义的用例是可能被执行的用例,它取决于控制宏SKIP_ALL_TEST
是否被定义,如果定义,那么BEGIN_TEST
所定义的用例就被一个哑巴函数代替,即不执行;如果未定义SKIP_ALL_TEST
,那么BEGIN_TEST
等同于RUN_GTEST
,就成为了一个将被执行的测试用例。
下面是这几个宏的定义(END_TEST仅仅是个花括号结束。)
实现
用法
输出
可以看到,只有使用RUN_GTEST
定义的h2被执行了。在用例的函数体里我不需要自己写log了。RUN_GTEST
会把测试用例名字给我打印出来。
解释
这里面代码最多的是RUN_GTEST
,它复杂在多了一个附加的参数__TAG__
, TEST只需要两个参数,RUN_GTEST
和BEGIN_TEST
为什么需要三个?
第三个参数是log里面常用的标志,用来标识这个测试用例,有了这个__TAG__
参数,我就可以灵活的标识一个测试用例,即使它混杂在若干用例的输出结果之中,通过这个__TAG__
`我也能一眼就看到它的输出。
如果不用TAG,那么每个用例开头,我都需要写一句输出语句:
使用RUN_GTEST
和TAG就可以这样写:
第三个参数__TAG__
是字符串”=”和”@”,从RUN_GTEST
的定义中可以看到,在刚一进入测试用例,__TAG__
会被输出10次,然后是__CASE__ ---> __SUB_CASE__
, 接着又是10次__TAG__
字符串的输出。如下:
如果不够明显,还可以使用更复杂的__TAG__
:
结论
使用RUN_GTEST
和BEGIN_TEST
这两个宏,就可以灵活控制哪个测试用例该被执行,哪个该“消失”。因为两个宏的参数是完全一样的,因此要想开启或关闭一个测试用例,使用RUN_GTEST
替换掉BEGIN_TEST
即可(关闭一个用例则执行相反的替换)。如果要打开所有用例,那直接定义SKIP_ALL_TEST
这个宏就可以了,不必挨个替换。
参考
gtest github主页
gtest samples
gtest 安装说明
在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问