TDD與VTDD系列(二):CppUnit的改進與使用(2)

4 測試過程框架


示例類定義以下:ide


class CMyClass
{
public:
    //加法函數
    int Add(int a, int b);函數

    //計算空調製冷器運行時間
    int WorkTime(int* pSecond);
};工具


加法函數Add()是入門示例,WorkTime()是接近應用的示例,功能是計算空調製冷器運行時間,需調用樁代碼取得環境溫度。測試過程,使用VC6.0。測試


假設CppUnit安裝目錄爲D:/CppUnit/CppUnit,被測試文件MyClass.cpp和MyClass.h位於D:/CppUnit/Project目錄。ui


一、用VC6.0創建一個一程,即測試工程。第一步左邊選擇MFC AppWizard(exe),工程名爲TestProject,存放位置與Project並列,即存放於D:/CppUnit/TestProject。第二步選擇Dialog based,點擊Finish。這個示例使用了圖形界面,因此要創建一個對話框工程。spa


二、把文件CppUnitPub.h和TestRun.cpp拷貝到D:/CppUnit/TestProject。orm


三、拷貝TestClassName.cpp和TestClassName.h文件到D:/CppUnit/TestProject,並重命名文件,將文件名中ClassName替換爲實際類名。這裏,被測試類名是CMyClass,所以,把文件名改成TestMyClass.cpp/.h。ci


用文本編輯工具如EditPlus打開這兩個文件,進行如下替換:
TestClassName替換爲TestMyClass。
ClassName替換爲CMyClass。
TestHeaderName替換爲TestMyClass.h。
HeaderName替換爲MyClass.h。產品


四、將二、3拷貝和修過的文件、以及被測試類的文件(即D:/CppUnit/Project目錄下的MyClass.cpp/.h)加入測試工程,方法是在VC6.0的Project菜單,單擊Add files…。


五、設置頭文件搜索目錄,包括CppUnit,以及產品項目的頭文件目錄:VC6.0->Project->Setting->C++,Category選擇Preprocessor,在Additional include directories中添加搜索目錄:D:/CPPUNIT/CPPUNIT/include,D:/CPPUNIT/Project。


六、加入CppUnit的靜態和動態庫。VC6.0->Project->Setting->Link,Category選擇Input,Application library path填寫D:/CPPUNIT/CPPUNIT/lib。將CppUnit目錄下的TestRunner.dll文件拷貝到D:/CppUnit/TestProject。


七、被測試函數WorkTime()調用了一個未實現的函數,要用樁來代替,後面再介紹樁代碼編寫,先把其中的代碼行success = GetTemperature(&temperature);前加上註釋符//。若是設定過程沒有錯誤,這時應該能夠經過編譯。


八、在CTestProjectApp::InitInstance()函中的開頭添加如下代碼:
void TestRunAll();
TestRunAll();
return FALSE;


九、在TestRun.cpp文件的TestRunAll()函數中加入測試類:runner.addTest(TestMyClass::GetSuite());


十、編寫CMyClass::Add()函數的測試函數,在TestMyClass.cpp文件中添加以下代碼:
void TestCMyClass::testAdd()
{
     CASE_BEGIN("");
     int a = 1;
     int b = 1;
     int ret = pObj->Add(a, b);
     CPPUNIT_ASSERT_EQUAL(2, ret);
     CASE_END();

 

     CASE_BEGIN("");
     int a = 10;
     int b = 10;
     int ret = pObj->Add(a, b);
     CPPUNIT_ASSERT_EQUAL(20, ret);
     CASE_END();
}


在TestMyClass.h文件中添加測試函數聲明void testAdd();並在CPPUNIT_TEST_SUITE宏內添加註冊代碼CPPUNIT_TEST(testAdd);


編譯並運行後會顯示CppUnit的圖形界面,點擊「Browse」,選擇要執行的測試,再點擊「Run」,即會顯示測試結果。因爲CMyClass::Add()函數中把+寫成了-,因此測試會失敗,修改後測試經過。


十一、編寫CMyClass::WorkTime()函數的測試函數,先把7所添加的註釋符刪除。這個函數首先調用int GetTemperature(int* pTemperature)函數取得環境溫度,而後根據環境溫度和預設的目標溫度的差,計算製冷器的運行時間。在TestMyClass.cpp添加測試函數:


extern int gExpectTemperature;
void TestMyClass::testWorkTime()
{
    CASE_BEGIN("failed");
    gExpectTemperature = 25;
    int second = 0;

    int ret = pObj->WorkTime(&second); 
    CPPUNIT_ASSERT_EQUAL(0, ret); 
    CPPUNIT_ASSERT_EQUAL(0, second); 
    CASE_END();

 

    CASE_BEGIN("ok-23");
    gExpectTemperature = 25;
    int second = 0;
    int ret = pObj->WorkTime(&second);
    CPPUNIT_ASSERT_EQUAL(0, ret);
    CPPUNIT_ASSERT_EQUAL(0, second);
    CASE_END();

 

    CASE_BEGIN("ok-28");
    gExpectTemperature = 25;
    int second = 0;
    int ret = pObj->WorkTime(&second);
    CPPUNIT_ASSERT_EQUAL(1, ret);
    CPPUNIT_ASSERT_EQUAL(180, second);
    CASE_END();

 

    CASE_BEGIN("ok-25");
    gExpectTemperature = 25;
    int second = 0;
    int ret = pObj->WorkTime(&second);
    CPPUNIT_ASSERT_EQUAL(0, ret);
    CPPUNIT_ASSERT_EQUAL(0, second);
    CASE_END();
}


在TestMyClass.h文件中添加測試函數聲明void testWorkTime ();並在CPPUNIT_TEST_SUITE宏內添加註冊代碼CPPUNIT_TEST(testWorkTime);


如今編譯還沒法經過,由於GetTemperature()未實現。假設咱們對GetTemperature()函數的測試需求以下表,要使用例與樁輸出匹配,如何編寫樁代碼呢?能夠用命名法來匹配用例與樁輸出。

 

用例

返回值

出參(環境溫度)

1

0(取環境溫度失敗)

 

2

1(取環境溫度成功)

23

3

1

25

4

1

28

  
在測試代碼中,每一個用例的第一行能夠給用例命名,如CASE_BEGIN("failed"),表示取環境溫度失敗,CASE_BEGIN("ok-23"),表示取環境溫度成功,值爲23。


在測試工程目錄下新建文件Stub.cpp,並加入測試工程,編寫樁代碼,以下:
#include "stdafx.h"
#include "CppUnitPub.h"

int GetTemperature(int* pTemperature)
{
    if(caseNameIs("failed"))
        return 0;

 

    if(caseNameIs("ok-23"))
    {
        *pTemperature = 23;
        return 1;
    }

 

    if(caseNameIs("ok-25"))
    {
        *pTemperature = 25;
        return 1;
    }

 

    if(caseNameIs("ok-28"))
    {
        *pTemperature = 28;
        return 1;
    }

 

    return 0;
}


樁代碼調用caseNameIs()來判斷當前用例名,並輸出合適的值。

本例中,若是GetTemperature()調用的是實際代碼,在測試時稱爲不可控,即沒法控制真實的環境溫度使其知足測試的須要;若是調用的是樁代碼,且樁代碼只是空函數,則稱爲失真,簡單的失真能夠用命名法解決,但不能解決複雜的失真,例如,GetTemperature()在同一用例中被屢次調用,每次要求輸出不一樣;或者樁與被測函數的關係是多對多,這就難於維護樁輸出與用例的關係了。另外,編寫樁代碼也不能解決不可控,假如GetTemperature()也是CMyClass類的成員函數,在不修改產品代碼的前提下,沒法調用樁。這些問題,就不是開源框架所能解決的了。

相關文章
相關標籤/搜索