使用gtest、或者cppunit之类的框架编写单元测试代码,一个最常见的问题是对类私有成员的测试与验证。理想情况下,我们希望在测试中,类中所有的数据与方法都是可以访问的;而在产品代码中,只暴露实现定义好的接口。
gtest官方文档中,也提到了对私有成员的处理,方法不外乎两种:一是使用friend关键字,骗取信任得以通行;二是重构采用Pimpl模式,公共类中只暴露接口,而实现类中暴露所有细节(public),测试时包含实现类即可。
但这两个方法都试了一下,觉不太方便。
- 使用friend关键字
gtest提供了一个FRIEND_TEST的宏,用来将一个test声明为产品类的友元。其缺点是显而易见的。一是需要往产品类中添加纯测试代码;二是每加一个test,需要在产品类中添加一项FRIEND_TEST。
- 重构采用Pimpl模式
我认可Pimpl模式,但同时我也不会对所有的类都这么做。所以如果让我只是为了支持测试而做这样的重构,我可能并不情愿。况且,手工重构很麻烦,而我手头也没有这么个自动化的工具。(当然,我相信这是可以自动化的)
其实我们想要达到的目的无非是:在产品代码中,该pubic的是public,该private的还是private;而在测试代码中,全部都是public。于是:
1 |
#ifdef GTEST |
2 |
#define private public |
3 |
#define protected public |
4 |
#endif |
将其放在每个类的声明前,或者放在一个单独的头文件如ForcePublic.h中并包含之。这样,在编译测试代码时,加上GTEST的预编译宏,就可以非常方便的使用被测试类中的任何成员了,并不会对产品代码产生任何的影响。
如果你是以纯源代码的方式使用你的产品类的,这个方法没有任何问题;但如果你是通过静态库,或者动态库的方式使用你的产品类的,在测试代码中若直接使用这些库,编译是没有问题,因为全伪装成了public,但在链接的时候,因为private的成员是没有从库中导出来的,必然会出现链接错误。此时有两个方案:一是以GTEST的方式重新编译库;二是直接将产品源代码编译进你的测试工程中去。
我使用的是动态库, 选择了将代码编译进测试工程的方法,为了解决dllexport, dllimport相关的一些编译问题,还做了如下定义:
1 |
#ifdef TXNMGR_EXPORTS |
2 |
#define TXNMGR_API __declspec(dllexport) |
3 |
#else |
4 |
#ifdef GTEST |
5 |
#define TXNMGR_API |
6 |
#else |
7 |
#define TXNMGR_API __declspec(dllimport) |
8 |
#endif |
9 |
#endif |
这样,在测试工程中,TXNMGR_API宏的定义为空,自然被忽略了,而不会影响到产品代码。
感觉着这种方法的好处在于只要在一开始做一些小小的修改,便可以一劳永逸的解决访问所有产品类所有私有成员的问题;由于我们改变的只是成员的访问级别,对类的行为应该没有什么影响。
更新:
在gtest的google group中就这个问题提出了讨论,大家指出这种方式的问题在于:
- 使得访问私有成员过分容易,从而导致写出来的test访问私有成员的可能性增大。测试访问了私有成员,也就是依赖于实现,这让单元测试成为你重构的负担,而不是保证。
- 万战勇同学也指出,这种方法是不标准的C++用法: 一是C++标准不允许重定义关键词,所以这种方法即使此时在你当前的编译器上是可行的,你也不能保证将来,或者在其他编译器上可行;二是public, protected private等访问修饰符可能会影响对象成员的布局,这样当你的测试是直接链接到产品代码时会有些问题。
所以,除非你对以上两点十分清楚并且可以接受,不然,还是使用官方的FRIEND_TEST要更好一些。
- 因为每一个需要访问私有成员的test都需要在产品代码上加上一项 FRIEND_TEST,这会让你思考:我真的需要访问私有成员吗?有没有不用访问私有成员的方法? 从而帮助形成更好的设计与测试
- 因为每一个依赖于实现的test都显式的登记在案,这样当你的实现细节有所改变时,你知道会影响哪些test
来自:http://www.cnblogs.com/baiyanhuang/archive/2010/06/28/1766820.html
相关推荐
有对类成员函数的例子
基于google gtest gmock的 实战教程。 演示,单元测试在C语言上 运用 简单上手,通俗易懂,提高代码质量,和编程效率
GTest测试框架是一个短小精湛的c/c++测试框架
gtest 单元测试框架 Google C++ Testing Framework(简称gtest,http://code.google.com/p/googletest/)是Google公司发布的一个开源C/C++单元测试框架,已被应用于多个开源项目及Google内部项目中,知名的例子包括...
利用谷歌gtest测试框架,搭建自己的测试用例
gtest单元测试的demo,这个示例展示了如何为具有多个成员函数的类编写更复杂的单元测试,通常,为类中的每个方法设置一个测试是一个好主意。您不必完全这样做,但这有助于组织您的测试。您还可以根据需要添加其他...
google gtest 测试 gtest框架的介绍与应用 googletest在linux下建立测试框架
研究学习gtest的框架
Gtest测试样本,可以根据此样本填写代码,适用于初学者学习
Google公司写的开源测试框架,基于C++语言,很实用的入门教程!
gtest单元测试PPT,讲解详细,可供参考
用 GTest 来测试MFC 程序 TDD开发 用 GTest 来测试MFC 程序 TDD开发 用 GTest 来测试MFC 程序 TDD开发
这个文档是我测试一个MFC_DLL的GTest测试工具使用方法,如有错漏请提出!欢迎评论留言,互相探讨!
自己根据需求写的一个c++单元测试框架,写这个基础是阅读了gtest源码和许多架构,和为了方便大家的需要,写的一个通用性框架。如果大家需要,可以修改里面的相关代码,实现自己的独特需求。
本资源为gtest单元测试框架源码,可以直接make编译,生成的静态文件,可以直接使用,有需要的可以下载一下。
gtest1.7编译支持unicode测试和MFC, 支持CString的使用
gtest是用于单元测试的工具,附件中包含gtest的安装包和使用文档两部分内容
win10搭建gtest测试环境+vs2019
这是一份使用gtest的示例代码,展示了testcase,testsuite,及多参数测试用例的用法。我使用的源码是gtest-1.6.0,这下面有一个文件夹fused-src,下面的gtest中包含有gtest.h.gtest_main.cc,gtest-all.cc三个文件,这...
gtest源码gtest源码