一、单元测试与CPPUNIT简介
几乎每个开发人员都写过测试代码,但是往往这些代码不系统,也没有良好的管理,同时在测试代码编写过程中也有很多重复的劳动,比较繁琐。在一个软件开发过程中,往往会进行很多修改,迭代开发的模型随处可见,如何验证程序的功能、性能和结构是否符合要求是一项重要的工作。
单元测试是属于白盒测试和结构性测试,一般由开发人员开展,当然如果有好的测试工具支持,测试人员甚至最终用户都可以参与。单元测试框架是编写和运行单元测试的软件工具,用来构建测试、运行测试、报告测试结果。对于C/C++开发,比较著名的收费单元测试工具是C++ Test,免费开源的则是CPPUNIT。
CPPUNIT是基于 LGPL 的开源项目,最初版本移植自 JUNIT ,是一个非常优秀的开源测试框架。CPPUNIT和 JUNIT 一样主要思想来源于极限编程。主要功能就是对单元测试进行管理,并可进行自动化测试。CPPUNIT设计遵循很多设计模式,代码结构也相对好理解。
二、CPPUNIT安装、使用和框架
1. 安装
CPPUNIT的主页是http://sourceforge.net/projects/cppunit/,从这里可以获取它的源代码cppunit-1.12.1.tar。安装过程如下:
1).解压 cppunit-1.12.0.tar.gz到C:/cppunit-1.12.1;
2).打开src/CppUnitLibraries.dsw,如果是VC 7及以上版本,会有一个对话框询问是否将工程转换成更高版本,选择“Yes to all”进行转换;
3).打开“Build”菜单,选择“Batch Build...”,弹出“Batch Build...”对话框后点击“Select All”,然后Build。
a.链接过程中会报错:
error C3505: cannot load type library '{80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}'
出错的文件是:src/msvc6/testrunner/MsDevCallerListCtrl.cpp。这是由于使用VC 8.0编译的缘故,需要修改一下它的源码,打开该文件,找到出错行(#67),将其替换为:
#if _MSC_VER >= 1400 // VC++ 8 or more //The following #import imports EnvDTE based on its LIBID. #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids //The following #import imports EnvDTE80 based on its LIBID. #import "libid:1A31287A-4D7D-413e-8E32-3B374931BD89" version("8.0") lcid("0") raw_interfaces_only named_guids #else // vc7 #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("7.0") lcid("0") raw_interfaces_only named_guids #endif |
b.另外还有一个错误:error C1189: #error : This add-in is for VC++ 6.0 only。发生这个错误的是工程“DSPlugIn”,这只是个插件,没有也不影响CPPUnit的使用,因此可以无视这条错误。再次编译,可以从lib文件夹中找到所有的静态库文件及动态库文件。
4).将include和lib文件夹加入到VC++的环境中。打开:Tools|Options|Projects and Solutions|VC++ Directories,将这两个文件夹的路径分别加入到Include files和Library files中。最好再将lib文件夹加入到系统环境变量PATH中,这样就不用再将其中的动态链接库拷到工程目录下而直接运行单元测试了。至此,CPPUnit的编译安装就完成了。
5).使用CPPUnitProjectWizard向导创建支持使用CPPUnit的测试类的Visual Studio 2005项目,用这个向导生成的代码,只是生成一个动态库,有DllPlugInTesterd_dll.exe来调取这个动态库测试,个人感觉用处不大。
安装向导
a. 下载 CPPUnitProjectWizard
http://cppunit.sourceforge.net/cppunit-wiki/CppUnitVisualStudio2005Wizard?action=AttachFile&do=get&target=CPPUnitProjectWizard.7z
b. 复制文件
CPPUnitProjectWizard.vsdir - 为向导命名
CPPUnitProjectWizard.vsz - 让VS8知道从哪里找到向导
到您的Visual Studio 8安装目录下的 VCProjects 文件夹中,C:/Program Files/Microsoft Visual Studio 8/VC/vcprojects。
c. 把整个CPPUnitProjectWizard解决方案文件夹复制到您的Visual Studio 8安装目录下的VCWizards文件夹中。
比如,我放在c:/Program Files/Microsoft Visual Studio 8/VC/VCWizards/CPPUnitProjectWizard/CPPUnitProjectWizard
或者,也可以放在你想放置的其它地方,然后编辑CPPUnitProjectWizard.vsz,定义参数 ABSOLUTE_PATH
Param="ABSOLUTE_PATH = c:/Program Files/Microsoft Visual Studio 8/VC/VCWizards/CPPUnitProjectWizard/CPPUnitProjectWizard"
d. 该项目需要定义环境变量 CPPUNITDIR
比如,我的环境变量 CPPUNITDIR= D:/cppunit-1.12.1
最后,修改 环境变量 %PATH%,在PATH路径中,增加 %CPPUNITDIR%/lib,以便程序加载时能找到 cppunit_dll.dll
e. 在开发环境中,设置好Include/Lib路径
%CPPUNITDIR%/Include
%CPPUNITDIR%/LIB
2. 使用
参考:
CppUnit测试框架入门 http://www.vckbase.com/document/viewdoc/?id=1258
Unit testing with CPPUnit http://www.codeproject.com/KB/library/Using_CPPUnit.aspx
visual studio 2005 wizard for cpp unit http://www.nabble.com/visual-studio-2005-wizard-for-cpp-unit-td4809724.html
3. 框架
本节把CPPUNIT的框架分为三个部分进行简单介绍。
1) 测试对象族
CPPUNIT的测试对象的类关系图:
Test:所有测试对象类的抽象基类,主要是定义run方法和统计子对象个数和查找遍历子对象的方法;
TestFixture:该类非常简单,只定义了两个方法setUp和tearDown,作为测试对象的准备和拆除方法,一般用户编写的测试类都直接继承它;
TestComposite、TestLeaf:根据设计模式中组合模式而设计的两个类,都继承自Test;
TestSuite:具体化了TestComposite的内容存储方式、添加子对象接口等等。该类对象包含了若干测试对象,作为测试对象的容器,而且可以嵌套;
TestRunner: 控制测试对象的构造和测试对象执行的类;
TestCase: 定义了一个测试对象要实现的具体接口,同时继承TestFixture的setUp和tearDown;
接口
TestCaller: 使用了设计模式中的策略模式,作为测试对象的最终封装类,提供了测试运行的策略,在测试执行中扮演了重要的角色。它是一个模板类。
2) 信息收集与显示族
CPPUNIT的测试信息收集与显示的类关系图
Outputter:是所有测试输出类的抽象基类,定义了write方法;
CompilerOutputter:以编译器信息类似方式输出测试信息,使用TestResultCollector获取测试信息;
TextOutputter:以文本流的方式输出测试信息,同样使用TestResultCollector获取测试信息;
TestListener:以设计模式中观察者模式定义了Observer所应该具有的从TestResult获取测试步骤信息的方法;
TestSuccessListener:实现了TestListener接口,同时继承了SynchronizedObject了从而具有线程安全性;
SynchronizedObject:该类实现了lock和unlock操作;
ExclusiveZone:使用SynchronizedObject进行了临界区的加锁和解锁操作;
TestResult:这个测试信息的收集者,在观察者模式中扮演Subject角色,是它把测试的各个步骤的信息通知到所有Listener对象的。
3)测试对象管理族
CPPUNIT测试对象管理类关系图
TestFactory:运用了设计模式中工厂设计模式,这里只定义了一个makeTest方法,是一个抽象基类;
TestSuiteFactory:该类继承自TestFactory,而且是模板类,是生成TestSuite对象的工厂;
TestFactoryRegistry:管理TestFactory对象的类(这里继承自TestFactory个人感觉有点不太恰当);
AutoRegisterSuite:模板类,自动把特定的TestSuiteFactory对象注册到TestFactoryRegistry对象;
TestSuiteBuilderContextBase、TestSuiteBuilderContext:用于构建测试对象的类,详细见代码分析部分。