注:此文档部分内容来源于cppunit源码解读,以及https://www.ibm.com/developerworks/cn/linux/l-cppunit/index.html与http://blog.csdn.net/freefalcon/article/details/753819参照该文档可以更好的理解cppunit的使用,无耻的加了原创
1.测试对象(Test,TestFixture,…):用于开发测试用例,以及对测试用例进行组织管理。
2.测试结果(TestResult):处理测试用例执行结果。TestResult与下面的TestListener采用的是观察者模式 (Observer Pattern)。
3.测试结果监听者(TestListener):TestListener作为TestResult的观察者,担任实际的结果处理角色。
4.结果输出(Outputter):将结果进行输出,可以制定不同的输出格式。
5.对象工厂(TestFactory):用于创建测试对象,对测试用例进行自动化管理。
6.测试执行体(TestRunner):用于运行一个测试。
在CppUnit中,一个或一组测试用例的测试对象被称为Fixture。Fixture就是被测试的目标,可能是一个对象或者一组相关的对象,甚至一个函数。(在此Fixture为下述函数中的GetAmount及GetCurrency)
有了被测试的 fixture,就可以对这个fixture 的某个功能、某个可能出错的流程编写测试代码,这样对某个方面完整的测试被称为TestCase(测试用例)。通常写一个 TestCase 的步骤包括:
(1).对 fixture 进行初始化,及其他初始化操作,比如:生成一组被测试的对象,初始化值;
(2).按照要测试的某个功能或者某个流程对 fixture 进行操作;
(3).验证结果是否正确;
(4).对fixture 的及其他的资源释放等清理工作。
对 fixture 的多个测试用例,通常(1)、(4)部分代码都是相似的,CppUnit 在很多地方引入了 setUp 和 tearDown 虚函数。可以在 setUp 函数里完成(1)初始化代码,而在 tearDown 函数中完成(4)代码。具体测试用例函数中只需要完成(2)(3)部分代码即可,运行时 CppUnit 会自动为每个测试用例函数运行 setUp,之后运行 tearDown,这样测试用例之间就没有交叉影响。
对 fixture 的所有测试用例可以被封装在一个 CppUnit::TestFixture 的子类(命名惯例是[ClassName]Test)中。然后定义这个fixture 的 setUp 和 tearDown 函数,为每个测试用例定义一个测试函数(命名惯例是 testXXX)
要把对 fixture 的一个测试函数转变成一个测试用例,需要生成一个 CppUnit::TestCaller 对象。而最终运行整个应用程序的测试代码的时候,可能需要同时运行对一个 fixture 的多个测试函数,甚至多个 fixture 的测试用例。CppUnit 中把这种同时运行的测试案例的集合称为 TestSuite。而 TestRunner 则运行测试用例或者 TestSuite,具体管理所有测试用例的生命周期。目前提供了 3 类TestRunner,包括:
CppUnit::TextUi::TestRunner // 文本方式的TestRunner,下述例子为文本方式
CppUnit::QtUi::TestRunner // QT方式的TestRunner
CppUnit::MfcUi::TestRunner // MFC方式的TestRunner
// 确信condition为真
CPPUNIT_ASSERT(condition)
// 当condition为假时失败, 并打印message
CPPUNIT_ASSERT_MESSAGE(message, condition)
// 当前测试失败, 并打印message
CPPUNIT_FAIL(message)
// 确信两者相等
CPPUNIT_ASSERT_EQUAL(expected, actual)
// 失败的同时打印message
CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual)
// 当expected和actual之间差大于delta时失败
CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)
// 判断执行表达式expression后是否抛出ExceptionType异常
CPPUNIT_ASSERT_THROW(expression, ExceptionType)
// 执行表达式expression后无异常抛出
CPPUNIT_ASSERT_NO_THROW(expression)
测试结果输出有三种,链接如下
https://www.ibm.com/developerworks/cn/linux/l-cppunit/index.html
此例用的是xml的输出方式,以xml输出的核心部分如下:
std::ofstream xmlFileOut("cpptestresults.xml");
CppUnit::XmlOutputter xmlOut(&result, xmlFileOut);
xmlOut.write(); //将结果写入xml
xmlFileOut.close();
1、Money.h
#ifndef _MONEY_H
#define _MONEY_H
#include
#include
using namespace std;
class CMoney
{
public:
CMoney( double amount, string currency )
: m_amount( amount )
, m_currency( currency )
{
}
~CMoney(){}
double GetAmount() const;
string GetCurrency() const;
private:
double m_amount;
string m_currency;
};
#endif
2、Money.cpp
#include
#include
#include "Money.h"
using namespace std;
double CMoney::GetAmount() const
{
return m_amount;
}
string CMoney::GetCurrency() const
{
return m_currency;
}
1、Money_Test.h
#ifndef _MONEY_TEST_H
#define _MONEY_TEST_H
#include "cppunit/extensions/HelperMacros.h"
#include "Money.h"
class CMoneyTest:public CppUnit::TestFixture
{
/*声明一个TestSuite*/
CPPUNIT_TEST_SUITE(CMoneyTest);
/*添加测试用例到TestSuite,定义新的测试用例都要在这里声明;
* 如果此处未声明某个测试用例,程序编译和运行都不会报错
* 仅仅是该测试用例不会被执行。
*/
CPPUNIT_TEST(testConstructor);
CPPUNIT_TEST(testOptorEqual);
CPPUNIT_TEST(testOptorNotEqual);
CPPUNIT_TEST(testOptorAdd);
/*TestSuite声明完成*/
CPPUNIT_TEST_SUITE_END();
public:
CMoneyTest(){}
/*初始化 */
void setUp();
/*清除动作 */
void tearDown();
/*test app in Money.cpp*/
/*test case */
void testConstructor();
};
#endif
2、Money_Test.cpp
#include "Money_Test.h"
#include "Money.h"
#include <string>
using namespace std;
/* 将该TestSuite注册到名字为“alltest”的TestSuite中,如果未定义会自动定义,也可以使用CPPUNIT_TEST_SUITE_REGISTRATION( MathTest );定义到全局未命名的TestSuite中 */
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CMoneyTest,"alltest");
/*初始化动作*/
void CMoneyTest::setUp()
{
}
/*清除动作*/
void CMoneyTest::tearDown()
{
}
/*编写测试用例,
* 此处编写一个用例分别来测试CMoney类的一个成员函数
* 如果有其他测试用例,继续添加即可
*/
/*test app in Money.cpp*/
/*test constructor*/
void CMoneyTest::testConstructor()
{
double dNum = 22124.44;
string sCurrency = "DD";
CMoney MyMoney(dNum, sCurrency);
CPPUNIT_ASSERT_EQUAL(dNum, MyMoney.GetAmount());
CPPUNIT_ASSERT_EQUAL(sCurrency, MyMoney.GetCurrency());
}
3、Money_Test_Main.cpp
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/XmlOutputter.h>
int main()
{
CppUnit::TestResult controller; //测试结果
CppUnit::TestResultCollector result; //收集结果
controller.addListener( &result ); //监听
CppUnit::TextUi::TestRunner runner; //测试文本类型
/*从注册的TestSuite获取特定的TestSuite,
没有参数的话则获取未命名的TestSuite*/
CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry("alltest");
/*添加这个TestSuite到TestRunner中*/
runner.addTest(registry.makeTest());
/*运行测试*/
runner.run( controller );
std::ofstream xmlFileOut("cpptestresults.xml"); //构造输出文件流
CppUnit::XmlOutputter xmlOut(&result, xmlFileOut);
xmlOut.write(); //将结果写入xml
xmlFileOut.close();
return 0;
}
1、g++ -lcppunit -ldl -o test Money_main.cpp Money_Test.cpp Money.cpp
2、如果是多文件项目,请编写makefile(可以根据原来的makefile微调即可,主要调整包含cpp的部分),并添加-lcppunit -ldl
什么叫做桩代码(测试桩),简而言之就是代替某些代码的代码。
如果测试中小型项目,只需把注册名字统一,然后不同类可以用不同cpp文件测试
目前暂时想到这么多,如后续遇到问题再补充,我们只能尽可能的多想到问题。