Linux下cppunit的基本使用说明文档及项目测试简介

Cppunit使用说明文档

注:此文档部分内容来源于cppunit源码解读,以及https://www.ibm.com/developerworks/cn/linux/l-cppunit/index.html与http://blog.csdn.net/freefalcon/article/details/753819参照该文档可以更好的理解cppunit的使用,无耻的加了原创

一、CppUnit核心内容主要包括六个方面:

1.测试对象(Test,TestFixture,…):用于开发测试用例,以及对测试用例进行组织管理。

2.测试结果(TestResult):处理测试用例执行结果。TestResult与下面的TestListener采用的是观察者模式 (Observer Pattern)。

3.测试结果监听者(TestListener):TestListener作为TestResult的观察者,担任实际的结果处理角色。

4.结果输出(Outputter):将结果进行输出,可以制定不同的输出格式。

5.对象工厂(TestFactory):用于创建测试对象,对测试用例进行自动化管理。

6.测试执行体(TestRunner):用于运行一个测试。

二、各模块的主要类继承结构

Linux下cppunit的基本使用说明文档及项目测试简介_第1张图片

三、CppUnit的原理

​ 在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 &registry = 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文件测试
目前暂时想到这么多,如后续遇到问题再补充,我们只能尽可能的多想到问题。

你可能感兴趣的:(C++)