C++之單元測試


      以前編寫程序從沒有做過單元測試的工作,所以在后期會花很多時間去糾錯,這也就是軟件工程中的2:8定律。最近要完成一個項目,要求要對系統中的主類和主函數作出單元測試的保證,才去查找了相關方面的資料,看過后覺得單元測試在工程中是必不可少的一項,下面就對有關C++的單元測試做一個簡單的介紹,因為本人還沒有系統的去理解相關方面的內容,所以只是介紹一些簡單的應用和淺顯的原理,有不到之處還請指出:

1) 什么是單元測試

     單元測試(unit test,模塊測試又稱白盒測試)是開發者編寫的一小段代碼,用於檢測被測代碼的一個很小的,很明確的功能是否正確,通過編寫單元測試可以在編碼階段發現程序編碼錯誤,甚至是程序設計錯誤。現在回想下我們平時編程的過程:梳理邏輯->編寫代碼->調bug的一個循環過程;其中調試bug是一個很耗費時間的過程,而且調完一堆bug后我們對自己程序的信任度卻在不斷降低,因為不知道還會不會出bug。這是因為我們所調試的bug只是當前出現的,沒有出現的呢,我們就說不好了。我們知道程序中一個簡單的if...else...語句都會對數據流有一次分類,不同類的數據流所對應的操作不同,想想這些你就會覺得自己的代碼還不知道要出多少bug。單元測試卻很好的解決了這個問題,你要做的就是對核心的函數,核心的邏輯,將所有可能的數據流都列出來,進行一次全覆蓋測試,這樣你代碼的健壯性就會很強。

2)如何寫單元測試

    最簡單的方法那就是自己將核心的函數抽出來,重新建立一個項目,提供所有可能的數據流入口,對函數進行測試。這樣做有兩個缺陷:1、只能處理一些簡單的項目,對於邏輯較為復雜,數據分支較多的就無法操作了;2、沒有一個很好的框架,寫出的代碼沒有一個統一的規則,可讀性不強;為此,依托一個現有的測試框架是必不可少的。CppUnit是xunit家族的一員,xunit是一種測試框架,最早是在smalltalk上實現,后來被廣泛的在各種語言上實現,除了Cppunit還有NUnit(c#版本)phpunit(php版本)和CppUnit相似的gtest(google的C++測試工具,據說在應用上要優於CppUnit,沒有用過,大家可以試試),cmockery(c語言測試工具,也是google的)。cppunit以源碼的方式發布,所以想要使用這個工具就要自己下載編譯(后面會介紹到),同時在windows下CppUnit還帶了一個MFC項目,可以以圖形界面的方式報告編譯情況。

3)如何編譯CppUnit

我的編譯環境是win7,vs2010;

 

1 :下載源碼包 最新的版本是1.21.1(2008年最后一次更新)

 

地址 :http://sourceforge.net/projects/cppunit/ 或者直接點擊 http://sourceforge.net/projects/cppunit/files/cppunit/1.12.1/cppunit-1.12.1.tar.gz/download

 

2 : 復制cppunt-1.12.1到c:\解壓得到目錄C:\cppunit-1.12.1

 

3 : 進入C:\cppunit-1.12.1\src 用VS2010打開CppUnitLibraries.dsw提示轉換,轉換之

 

4 : 在項目列表看見一堆項目,默認是以Debug的方式編譯,如以該方式編譯需要修改目標文件名

 

cppunit                $(ProjectName)   ->   $(ProjectName)d
cppunit_dll           $(ProjectName)   ->   cppunitd_dll
DllPlugInTester     $(ProjectName)   ->   $(ProjectName)d_dll
TestPlugInRunner $(ProjectName)   ->   $(ProjectName)d
TestRunner          $(ProjectName)  ->   $(ProjectName)d

 

需要修改目標文件名的原因是上述項目都設置了生成事件,在生成以后都會把生成的文件復制到lib目錄下,個人判斷d應該是代表了測試版的意思,如果是Release版本生成的目標文件都是項目名不需要修改

 

5 : 修改DSPlugIn入口
屬性,配置屬性,鏈接器,高級,無入口點 設置是

 

6 : 修改無法加載類型庫(編譯TestPlugInRunner,TestRunner)會報錯其中7.0修改為8.0
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("7.0") lcid("0") raw_interfaces_only named_guids

 

以上設置都全做完以后就可以整體編譯解決方案了(這里要注意一點,要將上述所有的配置實現后再編譯,不要對每個項目進行單獨編譯;否則會出現諸如“該文件沒有一個關聯的程序...”這樣的問題)

4)如何用Cppunit

先寫一個測試的Demo,初步體驗下Cppunit的用法

1、打開vs2010文件項, 新建VC++空項目:cppUnitTest

2、 設置環境變量;在系統變量PATH的尾巴上添加“C:\cppunit-1.12.1”(這是我的地址)

3、 [項目cppUnitTest]-[屬性]-[配置屬性]-[C/C++]-[常規]-[附加包含目錄]: "../include"

4、 [項目cppUnitTest]-[屬性]-[配置屬性]-[鏈接器]-[常規]-[附加庫目錄]: "../lib"

5、 [項目cppUnitTest]-[屬性]-[配置屬性]-[鏈接器]-[輸入]-[附加依賴項]: "cppunitd.lib"

6、新建文件main.cpp

#include <cppunit/TestCase.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestRunner.h>

// 定義測試類
class StringTest : public CppUnit::TestFixture
{
public:
    void setUp() // 初始化
    {
        m_str1 = "Hello, world";
        m_str2 = "Hi, cppunit";
    }

    void tearDown() // 清理
    {
    }

    void testSwap() // 測試方法1
    {
        std::string str1 = m_str1;
        std::string str2 = m_str2;
        m_str1.swap(m_str2);
        
        CPPUNIT_ASSERT(m_str1 == str2);
        CPPUNIT_ASSERT(m_str2 == str1);
    }

    void testFind() // 測試方法2
    {
        int pos1 = m_str1.find(',');
        int pos2 = m_str2.rfind(',');

        CPPUNIT_ASSERT_EQUAL(5, pos1);
        CPPUNIT_ASSERT_EQUAL(2, pos2);
    }

protected:
    std::string     m_str1;
    std::string     m_str2;
};

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 准備好結果收集器 

    CppUnit::TestRunner runner; // 定義執行實體
    runner.addTest(new CppUnit::TestCaller<StringTest>("testSwap", &StringTest::testSwap)); // 構建測試用例1
    runner.addTest(new CppUnit::TestCaller<StringTest>("testFind", &StringTest::testFind)); // 構建測試用例2
    runner.run(r); // 運行測試

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結果輸出

    return rc.wasSuccessful() ? 0 : -1;
}

以上代碼時使用Cppunit框架對string類的兩個函數進行測試,在testFind()中調用string的find函數並通過CPPUNIT_ASSERT對結果進行測試;

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM