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):用於運行一個測試。
二、各模塊的主要類繼承結構
三、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 <iostream>
#include <string>
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 <iostream>
#include <string>
#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文件測試
目前暫時想到這麼多,如後續遇到問題再補充,我們只能儘可能的多想到問題。