下面是單元測試類的定義:
#if !defined(DISKDATA_TESTCASE_H_INCLUDED)
#define DISKDATA_TESTCASE_H_INCLUDED
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <cppunit/TestCase.h>//為了從基類TestCase派生新的測試類
#include <cppunit/extensions/HelperMacros.h>//方便快速定義測試類的宏
#include "DiskData.h"
class DiskDataTestCase : public CppUnit::TestCase
{
CPPUNIT_TEST_SUITE(DiskDataTestCase);//定義Test Suite的起點(diǎn)
CPPUNIT_TEST(loadTest);//定義Test Case
CPPUNIT_TEST(storeTest);
CPPUNIT_TEST_SUITE_END();//定義Test Suite的終點(diǎn)
public:
void setUp();
void tearDown();
protected:
void loadTest();
void storeTest();
private:
DiskData *fixture;
};
#endif
例程中,DiskDataTestCase類重載了兩個方法:setUp()和tearDown()。這兩個方法在Test Case開始和結(jié)束的時候自動運(yùn)行。
測試邏輯是在兩個Protected方法中實(shí)現(xiàn)的,稍后要涉及到如何為測試邏輯編碼。
例程的后定義了指向DiskData類型數(shù)據(jù)的指針fixture,用以保存測試過程中的目標(biāo)對象。setUp()是初始化函數(shù),在調(diào)用每一個Test Case之前調(diào)用setUp(),同時負(fù)責(zé)初始化目標(biāo)對象。Test Case運(yùn)行過程中要使用fixture。在每一個Test Case運(yùn)行結(jié)束之后,調(diào)用tearDown()銷毀fixture。這樣,每次運(yùn)行Test Case時所使用的都是新產(chǎn)生的fixture。
測試步驟如下:
開啟測試程序
點(diǎn)擊“Run”按鍵
調(diào)用setUp()方法:初始化fixture
調(diào)用第一個Test Case函數(shù)
調(diào)用tearDown()方法:釋放fixture
調(diào)用setUp()方法:初始化fixture
調(diào)用第二個Test Case函數(shù)
調(diào)用tearDown()方法:釋放fixture
...
經(jīng)過編碼:
#include "DiskDataTestCase.h"
CPPUNIT_TEST_SUITE_REGISTRATION(DiskDataTestCase);
void DiskDataTestCase::setUp()
{
fixture = new DiskData();
}
void DiskDataTestCase::tearDown()
{
delete fixture;
fixture = NULL;
}
void DiskDataTestCase::loadTest()
{
// our load test logic
}
void DiskDataTestCase::storeTest()
{
// our store test logic
}
現(xiàn)在,編碼已經(jīng)變得非常簡單了:setUp()和tearDown()實(shí)現(xiàn)了創(chuàng)建、釋放fixture,下面要做的是為loadTest()、storeTest()編碼了。
Test Case編碼
搞清楚需要測試那些方面之后的工作是編碼實(shí)現(xiàn)。可以通過使用庫函數(shù)、第三方庫函數(shù)、Win32 API或者C/C++操作符和指令的內(nèi)部屬性。
有時需要輔助的文件或者數(shù)據(jù)庫表來存儲正確的數(shù)據(jù)。在本例中,通過對比內(nèi)部不數(shù)據(jù)和外部文件的數(shù)據(jù)來判斷結(jié)果是否正確。
當(dāng)出現(xiàn)錯誤時(比如內(nèi)部數(shù)據(jù)和外部數(shù)據(jù)不同),需要拋出異常?梢酝ㄟ^CPPUNIT_FAIL(message)宏實(shí)現(xiàn),也可以通過assertions宏實(shí)現(xiàn)。
以下是一些常用的assertion宏:
CPPUNIT_ASSERT(condition): 檢查condition,如為false,拋出異常
CPPUNIT_ASSERT_MESSAGE(message, condition): 檢查condition,如為false,拋出異常,并顯示預(yù)先設(shè)定的信息
CPPUNIT_ASSERT_EQUAL(expected,current): 檢查expected與current的值是否相等,拋出異常,顯示expected和current的值
CPPUNIT_ASSERT_EQUAL_MESSAGE(message,expected,current): 檢查expected的值與actual的值是否相等,拋出異常,顯示expected,current的值,并顯示預(yù)先設(shè)定的信息
CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,current,delta): 檢查expected, current之差是否小于delta,如果不小于,顯示expected和current的值
下面講一下loadTest編碼的編碼構(gòu)想:首先需要一個外部文件,其中存儲這一個DATA型數(shù)據(jù),文件的創(chuàng)建方式并不重要,關(guān)鍵是要保證里面的數(shù)據(jù)的正確性。然后,要進(jìn)行的操作是檢查load函數(shù)從外部文件中讀出的數(shù)據(jù)和實(shí)現(xiàn)存在其中的數(shù)據(jù)是否一致。代碼如下:
//
// 前提:外部文件中已存儲了正確的數(shù)據(jù)。
//
#define AUX_FILENAME "ok_data.dat"
#define FILE_NUMBER 19
#define FILE_STRING "this is correct text stored in auxiliar file"
void DiskDataTestCase::loadTest()
{
// 相對路徑轉(zhuǎn)化為路徑
TCHAR absoluteFilename[MAX_PATH];
DWORD size = MAX_PATH;
strcpy(absoluteFilename, AUX_FILENAME);
CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &size) );
// 執(zhí)行操作
CPPUNIT_ASSERT( fixture->load(absoluteFilename) );
// 通過assertion檢查運(yùn)行結(jié)果
LPDATA loadedData = fixture->getData();
CPPUNIT_ASSERT(loadedData != NULL);
CPPUNIT_ASSERT_EQUAL(FILE_NUMBER, loadedData->number);
CPPUNIT_ASSERT( 0 == strcmp(FILE_STRING,
fixture->getData()->string) );
}