CppUnit是一个开源的、跨平台的用于C++的单元测试工具。本文以VC6和VC8为例,简单介绍其使用方法。
首先,到 http://sourceforge.net/project/showfiles.php?group_id=11795 下载回CppUnit的最新源代码(当前最新版1.12.0)和文档。将源码包解压,在源代码包子目录src下已经配置好了VC6的工程文件。
如果使用VC6,那么直接用VC6打开VC工程文件,选择Batch Build(最好自己对工程参数重新设置一下),然后就可以在源代码包子目录Lib中得到我们需要的库文件。如果使用VC8,那么用VC8打开VC6工程 文件,并按提示直接转换成.net版本。同样,选择批生成,生成我们需要的库文件。在VC8中编译源代码时会出现编译错误“#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("7.0") lcid("0") raw_interfaces_only named_guids”,将version("7.0")改为version("8.0")即可。
在开发应用程序过程中,我们可能会使用到很多第三方程序库,如这里的CppUnit。为了方便,我们可以建立一个第三方程序库的专用文件夹,并为具体的程 序库(如这里的CppUnit)建立子文件夹。然后在VC的Option中分别设置库的头文件路径和库文件连接路径。如果有Dll文件,则在系统变量 PATH中加进DLL文件所在目录,这样,程序运行时就能搜索到该DLL文件并加载(注意,只有VC重启后,PATH设置才会对从VC里直接运行的程序生 效)。同样,这里我们也把CppUnit的头文件和库文件路径加到VC的默认搜索路径中。
另外,需要指出,一般情况下,Dll文件是需要与生成的程序一同发布的,此时就必须将Dll文件拷贝到Project目录中。此时,可以采取手动方式,也可以在Project的Post-Build Step中添加命令执行拷贝动作。
在VC中使用CppUnit进行单元测试时,可以选择CppUnit的控制台测试作界面和图形测试界面。控制台界面简洁,而图形界面较直观,并且借助 CppUnit提供的插件可以快速定位到断言失败的地方。一般情况下,我们使用控制台测试界面来测试Console程序,使用图形测试界面来测试GUI程 序,这样测试Project不会影响被测试的Project。由于图形测试界面的易用性,我们可能也希望用它来测试Console程序,此时稍微麻烦一 点。下面分别介绍这几种用法(以VC6为例,VC8类似)。
在下面的叙述中,把被测试Project叫做目标Project,把被测试类叫做目标类。
****** 使用CppUnit的Console测试界面测试Console程序 ******
1. 创建一个工作区用于开发和测试,然后在该工作区中分别创建两个Project,一个用于开发,另一个用于测试。
2. 在测试Project中,设置如下:
(1)设置连接库:cppunit.lib(Release版)和 cppunitd.lib(Debug版),或者使用动态链接库版本cppunit_dll.lib、cppunit_dll.dll和 cppunitd_dll.lib、cppunitd_dll.dll;
(2)在C/C++的Code Generation中设置Use run-time library为Multithreaded Dll(Release版)和Debug Multithreaded Dll(Debug版)。
3. 为测试Project添加测试类,假如被测试的目标类为Demo,那么可以定义一个DemoTest的测试类:
文件DemoTest.h:
#ifndef DEMO_TEST_H
#define DEMO_TEST_H
#include "cppunit/extensions/HelperMacros.h"
class DemoTest: public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(DemoTest); // 参数为本测试类名
CPPUNIT_TEST(testFunc); // 参数为测试函数名,与下面声明的测试函数对应
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
// 在这里进行测试的初始化工作
}
void tearDown() {
// 在这里进行测试完毕后的清理工作
}
void testFunc(); // 测试函数,用来测试目标类的某一个细节
};
#endif // DEMO_TEST_H
文件DemoTest.cpp:
#include "DemoTest.h"
#include "../Demo/DemoTest.h" // 这里为要测试的目标类的头文件路径,因为测试时要用到Demo类
#include <cppunit/extensions/HelperMacros.h>
CPPUNIT_TEST_SUITE_REGISTRATION(DemoTest);
void DemoTest::testFunc()
{
// 这里对Demo类进行测试,可以使用CPPUNIT_ASSERT、CPPUNIT_ASSERT_EQUAL等来断言
}
4. 由于测试类中要用到目标类,所以需要把目标类的实现文件加入到测试Project中,但不用加入目标类的头文件,这样在测试Project中的类视图中就不会出现目标类。
5. 在测试Project中,新建一个源文件,用来写测试的main函数,测试框架如下:
#include "DemoTest.h"
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
int main()
{
CppUnit::TextUi::TestRunner runner;
CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
runner.run();
return 0;
}
6. 运行测试Project,就可以看到测试结果。在测试运行时,如果测试函数中某一断言失败,则此函数执行中断,此测试函数中后面的断言不会被执行。因此,应该尽可能压缩测试函数,使其测试功能单一。
7. 注意,在该测试方案中,并没有对被测试Project有任何要求或者修改。被测试Project可以是一个完整的工程(会生成自己的执行程序),也可以只是一个Dll Project或者仅有类的实现。
****** 使用CppUnit的GUI测试界面测试GUI程序 ******
1. 创建测试Project为基于Dialog的MFC Project。然后,设置测试Project的连接库cppunitd.lib和testrunnerd.lib(Debug版)(同样设置 Release版,选择相应版本库文件)。CppUnit的GUI版本还需要使用TestRunnerd.dll文件。如果在系统环境变量PATH中没有 TestRunner.dll文件所在目录,那么需要把TestRunnerd.dll文件拷贝到测试Project目录下。另外,这里不需要设置代码的 运行库,因为MFC Project默认就是Multithreaded Dll运行库。
2. 与Console测试方案一样,添加测试类。
3. 找到App类的InitInstance函数,把原来用于显示对话框的代码替换为如下代码:
CppUnit::MfcUi::TestRunner runner;
CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
runner.run(); //show UI
并加上头文件:
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/mfc/TestRunner.h>
4. 此时,编译运行就可出现图形测试界面,在Browse里面选择要测试的树(在CppUnit中所以测试被组织为了颗树),然后点击Run即可运行测试。
5. 为了快速定位失败的断言,CppUni提供了专门的插件用于GUI方案,在VC6的Tools|Customize|Add-ins and Macro Files中添加CppUnit的TestRunnerDSPlugIn.dll。然后,双击失败的断言即可定位到相应的源代码。
****** 使用CppUnit的GUI测试界面测试Console程序 ******
由于GUI测试界面的易用性,我们可能也希望用它来测试Console程序。如果直接用上面的默认GUI方案去测试Console程序,则需要修改被测试 Project(要在源文件添加stdafx.h头文件),违背了测试的原则(被测试Project不应该感知测试Project的存在的)。为了解决这 个不足,同时仍保留GUI方案的直观性与方便性,我们可以定制自己的GUI测试方案。具体过程如下:
1. 同样,建立测试工作区,然后建立Console目标Project(被测试Project)和空的Win32(不是MFCProject!)测试 Project。然后,在测试Project的Project Setting中设置General为Use MFC in a Shared DLL,设置链接库cppunitd.lib testrunnerd.lib (Debug版)[将testrunnerd.dll拷贝到测试Project目录下]。
2. 同样,添加测试类。
3. 写一个TestApp类(可以用于所有测试,不用修改),如下:
TestApp.h文件:
#ifndef TEST_APP_H
#define TEST_APP_H
#include <afxwin.h>
class TestApp: public CWinApp
{
public:
virtual BOOL InitInstance();
};
#endif // TEST_APP_H
TestApp.cpp文件:
#include "TestApp.h"
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/mfc/TestRunner.h>
BOOL TestApp::InitInstance()
{
CppUnit::MfcUi::TestRunner runner;
CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
runner.run(); //show UI
return FALSE;
}
TestApp theApp;
4.然后,编译、运行程序即可。此时,测试Project不再需要被测试Project的源文件包含头文件stdafx.h。
****** 建立Post-build测试机制 ******
如果我们希望程序编译完成后自动运行测试,那么我们就可以 利用Post-build测试机制。
在VC6的Project|Settings对话框的Post-build step标签下,在Post-build command中添加一行:$(TargetPath),$(TargetPath)将展开为你的应用程序名(包括路径)。同时,修改程序的main函 数,如果main返回非0,则表示此“Build”失败;返回0表示成功。同样,在VC8中的工程设置中也有对应项供设置。