一. CppUnit的安装
从http://sourceforge.net/projects/cppunit CppUnit的源码包. CppUnit是开源产品 , 当前最高版本为1.11.0. (在上面的链接所指向的页面上选择 Development Snapshot ).
下载后,将源码包解压缩到本地硬盘. 以C:为例, 解压到C:\CppUnit-1.11.0 . 接下来进行编译工作. 在src/目录下, 将CppUnitLibraries.dsw工程文件用vc 打开. 因为这个工程是vc6建的工程, 所以会提示是否将此工程转为vc.net的工程格式. 选择"全是"就行. 然后在"生成"菜单中选择"生成解决方案",编译整个工程.
编译通过以后, 在lib/目录下,会生成若干lib,和dll文件, 都以cppunit开头. cppunitd表示debug版, cppunit表示release版.
然后配置vc环境: 工具菜单->选项->项目->vc++目录, 将C:\cppunit-1.11.0\include加入到vc 的 头文件目录中. 将C:\cppunit-1.11.0\lib 加入到vc的 连接库目录中. 然后将 C:\cppunit-1.11.0\lib路径加入到系统路径中(因为我们的测试程序需要cppunit的dll文件,所以要dll所在路径加入到系统路径(path)变量中, 或者将这些文件拷贝到系统目录中也可以).
二. CppUnit 的使用
以上工作完成以后,就可以正式使用CppUnit了.
我们新建一个控制台工程, 假定工程名为TDD1. 假设我们将在这个工程下开发, 那么根据测试驱动的原理,我们需要先建立一个单元测试框架. 在CppUnit下, 可以选择控制台方式和UI方式两种表现方案.我们选择UI方式. 那么现在在原来工程的基础上,再新增加一个对话框工程. 假设名为:Unit_Test .
在CppUnit中, 是以TestCase为最小的测试单位, 若干TestCase组成一个TestSuite. 所以我们要先建立一个TestCase.
新建一个类, 命名为CTestCase , 让其从CppUnit::TestCase派生. 为其新增一个方法,假设为 void doTest(); 我们将在这个函数中写入我们的一些测试代码. 切记要包含头文件
#include <CppUnit/extensions/HelperMacros.h>
class CTestCase : public CppUnit::TestCase
{
public:
CTestCase(void);
~CTestCase(void);
void doTest();
};
接下来, 我们要对我们的TestCase进行声明. 声明用到了三个宏.
CPPUNIT_TEST_SUITE();
CPPUNIT_TEST();
CPPUNIT_TEST_SUITE_END();
第一个宏声明一个测试包,第二个宏声明一个测试用例. 现在我们的CTestCase类看上去象这样.
class CTestCase : public CppUnit::TestCase
{
CPPUNIT_TEST_SUITE(CTestCase);
CPPUNIT_TEST(doTest);
CPPUNIT_TEST_SUITE_END();
public:
CTestCase(void);
~CTestCase(void);
void doTest();
};
接下来,我们要注册我们的测试suite. 使用CPPUNIT_TEST_SUITE_NAMED_REGISTRATION()来注册一个测试suite. 这个宏的第二个参数是我们注册的suite的名字. 在这里我们可以用字符串来代替, 但我们用一个静态函数来返回这个suite的名字.
//TestCase.h
static std::string getSuiteName();
//TestCase.cpp
std::string CTestCase::getSuiteName()
{
return "TDDExample3";
}
记得要在TestCase.h中包含 #include <string>
然后在 TestCase.cpp注册我们的suite.
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CTestCase , CTestCase::getSuiteName() );
接下来我们写一个注册函数, 使其在运行期生成一个Test.
static CppUnit::Test* getSuite();
CppUnit::Test* CTestCase::getSuite()
{
CppUnit::TestFactoryRegistry& reg =
CppUnit::TestFactoryRegistry::getRegistry ( CTestCase::getSuiteName() );
return reg.makeTest();
}
记住包含头文件:
#include <cppunit/extensions/TestFactoryRegistry.h>
最后, 我们的单元测试建立一个UI测试界面.
我们在CUnit_TestApp::InitInstance()函数中,将原先显示主对话框的代码以下面的代码取代:
CppUnit::MfcUi::TestRunner runner;
runner.addTest(CTestCase::getSuite());
runner.run();
必须先包含头文件:
#include <cppunit/ui/mfc/TestRunner.h>
#include "TestCase.h"
到此为止, 我们已经建立好一个简单的单元测试框架. 我们可以在doTest()中加入我们的测试代码,来进行测试了. CppUnit会将测试结果通过一个界面显示出来.
但此时我们虽然能编译通过,但在连接时会发生错误. 所以将下面两个库加入到工程中. 也可以在TestCase.h 中显式的加入:
#pragma comment(lib,"cppunit.lib")
#pragma comment(lib,"testrunnerd.lib")
下面是完整的程序清单:
//TestCase.h
#pragma once
#include <string>
#include <CppUnit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/Asserter.h>
#pragma comment(lib,"cppunit.lib")
#pragma comment(lib,"testrunnerd.lib")
class CTestCase : public CppUnit::TestCase
{
CPPUNIT_TEST_SUITE(CTestCase);
CPPUNIT_TEST(doTest);
CPPUNIT_TEST_SUITE_END();
public:
static std::string getSuiteName();
static CppUnit::Test* getSuite();
public:
CTestCase(void);
~CTestCase(void);
void doTest();
};
//TestCase.Cpp
#include "StdAfx.h"
#include ".\testcase.h"
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CTestCase , CTestCase::getSuiteName() );
CTestCase::CTestCase(void)
{
}
CTestCase::~CTestCase(void)
{
}
void CTestCase::doTest()
{
}
std::string CTestCase::getSuiteName()
{
return "TDDExample3";
}
CppUnit::Test* CTestCase::getSuite()
{
CppUnit::TestFactoryRegistry& reg =
CppUnit::TestFactoryRegistry::getRegistry( CTestCase::getSuiteName() );
return reg.makeTest();
}
//Unit_Test.cpp
#include <cppunit/ui/mfc/TestRunner.h>
#include "TestCase.h"
BOOL CUnit_TestApp::InitInstance()
{
InitCommonControls();
CWinApp::InitInstance();
AfxEnableControlContainer();
CppUnit::MfcUi::TestRunner runner;
runner.addTest(CTestCase::getSuite());
runner.run();
return FALSE;
}
现在编译,运行, 如图一:
进度条呈现绿色, 表示我们此次测试通过. 事实上我们的doTest是一个空函数,什么代码也没有写,当然能通过了. :)
下面我们在doTest()中加点代码进去.
char* p = NULL; p[0]='c';
这段代码会引起一个访问异常. 看UnitCpp怎么来报告这段代码的错误.
编译,运行如图2:
这时CppUnit会告诉我们dotest出现一个错误. 并提供了错误的一些信息.
这样我们用CppUnit搭建一个简单单元测试框架.
参考文章: