<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    如何用googletest寫C++單元測試

     googletest是一個用來寫C++單元測試的框架,它是跨平臺的,可應用在windows、linux、Mac等OS平臺上。下面,我來說明如何使用最新的1.6版本gtest寫自己的單元測試

      本文包括以下幾部分:1、獲取并編譯googletest(以下簡稱為gtest);2、如何編寫單元測試用例;3、如何執行單元測試。4、google test內部是如何執行我們的單元測試用例的。

      1. 獲取并編譯gtest

      gtest試圖跨平臺,理論上,它就應該提供多個版本的binary包。但事實上,gtest只提供源碼和相應平臺的編譯方式,這是為什么呢?google的解釋是,我們在編譯出gtest時,有些獨特的工程很可能希望在編譯時加許多flag,把編譯的過程下放給用戶,可以讓用戶更靈活的處理。這個仁者見仁吧,反正也是免費的BSD權限。

      源碼的獲取地址:http://code.google.com/p/googletest/

      svn checkout

      怎么編譯呢?

      先進入gtest目錄(解壓gtest.zip包過程就不說了),執行以下兩行命令:

    Changes for 1.6.0:

    * New feature: ADD_FAILURE_AT() for reporting a test failure at the
      given source location -- useful for writing testing utilities.
    。。。 。。。
    Bug fixes and implementation clean-ups.
    * Potentially incompatible changes: disables the harmful 'make install'
      command in autotools.

      就是最下面一行,make install禁用了,郁悶了吧?UNIX的習慣編譯方法:./configure;make;make install失靈了,只能說google比較有種,又開始挑戰用戶習慣了。

      那么怎么編譯呢?

      先進入gtest目錄(解壓gtest.zip包過程就不說了),執行以下兩行命令:

    g++ -I./include -I./ -c ./src/gtest-all.cc
    ar -rv libgtest.a gtest-all.o

      之后,生成了libgtest.a,這個就是我們要的東東了。以后寫自己的單元測試,就需要libgtest.a和gtest目錄下的include目錄,所以,這1文件1目錄我們需要拷貝到自己的工程中。

      編譯完成后怎么驗證是否成功了呢?(相當不友好!)

    cd ${GTEST_DIR}/make
      make

    如果看到:

    Running main() from gtest_main.cc
    [==========] Running 6 tests from 2 test cases.
    [----------] Global test environment set-up.
    [----------] 3 tests from FactorialTest
    [ RUN      ] FactorialTest.Negative
    [       OK ] FactorialTest.Negative (0 ms)
    [ RUN      ] FactorialTest.Zero
    [       OK ] FactorialTest.Zero (0 ms)
    [ RUN      ] FactorialTest.Positive
    [       OK ] FactorialTest.Positive (0 ms)
    [----------] 3 tests from FactorialTest (0 ms total)

    [----------] 3 tests from IsPrimeTest
    [ RUN      ] IsPrimeTest.Negative
    [       OK ] IsPrimeTest.Negative (0 ms)
    [ RUN      ] IsPrimeTest.Trivial
    [       OK ] IsPrimeTest.Trivial (0 ms)
    [ RUN      ] IsPrimeTest.Positive
    [       OK ] IsPrimeTest.Positive (0 ms)
    [----------] 3 tests from IsPrimeTest (0 ms total)

    [----------] Global test environment tear-down
    [==========] 6 tests from 2 test cases ran. (0 ms total)
    [  PASSED  ] 6 tests.

      那么證明編譯成功了。

      2、如何編寫單元測試用例

      以一個例子來說。我寫了一個開地址的哈希表,它有del/get/add三個主要方法需要測試。在測試的時候,很自然,我只希望構造一個哈希表對象,對之做許多種不同組合的操作,以驗證三個方法是否正常。所以,gtest提供的TEST方式我不會用,因為多個TEST不能共享同一份數據,而且還有初始化哈希表對象的過程呢。所以我用TEST_F方式。TEST_F是一個宏,TEST_F(classname, casename){}在函數體內去做具體的驗證。

      上面是我要執行單元測試的類圖。那么,我需要寫一系列單元測試用例來測試這個類。用gtest,首先要聲明一個類,繼承自gtest里的Test類:

    代碼很簡單:

    class CHashTableTest : public ::testing::Test {
    protected:
     CHashTableTest():ht(100){

     }
     virtual void SetUp() {
      key1 = "testkey1";
      key2 = "testkey2";
     }

     // virtual void TearDown() {}
     CHashTable ht;

     string key1;
     string key2;
    };

      然后開始寫測試用例,用例里可以直接使用上面類中的成員。

    TEST_F(CHashTableTest, hashfunc)
    {
     CHashElement he;

     ASSERT_NE(\
       ht.getHashKey((char*)key1.c_str(), key1.size(), 0),\
       ht.getHashKey((char*)key2.c_str(), key2.size(), 0));

     ASSERT_NE(\
       ht.getHashKey((char*)key1.c_str(), key1.size(), 0),\
       ht.getHashKey((char*)key1.c_str(), key1.size(), 1));

     ASSERT_EQ(\
       ht.getHashKey((char*)key1.c_str(), key1.size(), 0),\
       ht.getHashKey((char*)key1.c_str(), key1.size(), 0));
    }

      注意,TEST_F宏會直接生成一個類,這個類繼承自上面我們寫的CHashTableTest類。

      gtest提供ASSERT_和EXPECT_系列的宏,用于判斷二進制、字符串等對象是否相等、真假等等。這兩種宏的區別是,ASSERT_失敗了不會往下執行,而EXPECT_會繼續。

      3、如何執行單元測試

      首先,我們自己要有一個main函數,函數內容非常簡單:

    #include "gtest/gtest.h"

    int main(int argc, char** argv) {
     testing::InitGoogleTest(&argc, argv);

     // Runs all tests using Google Test.
     return RUN_ALL_TESTS();
    }

      InitGoogleTest會解析參數。RUN_ALL_TESTS會把整個工程里的TEST和TEST_F這些函數全部作為測試用例執行一遍。

      執行時,假設我們編譯出的可執行文件叫unittest,那么直接執行./unittest就會輸出結果到屏幕,例如:

    [==========] Running 4 tests from 1 test case.
    [----------] Global test environment set-up.
    [----------] 4 tests from CHashTableTest
    [ RUN      ] CHashTableTest.hashfunc
    [       OK ] CHashTableTest.hashfunc (0 ms)
    [ RUN      ] CHashTableTest.addget
    [       OK ] CHashTableTest.addget (0 ms)
    [ RUN      ] CHashTableTest.add2get
    testCHashTable.cpp:79: Failure
    Value of: getHe->m_pNext==NULL
      Actual: true
    Expected: false
    [  FAILED  ] CHashTableTest.add2get (1 ms)
    [ RUN      ] CHashTableTest.delget
    [       OK ] CHashTableTest.delget (0 ms)
    [----------] 4 tests from CHashTableTest (1 ms total)

    [----------] Global test environment tear-down
    [==========] 4 tests from 1 test case ran. (1 ms total)
    [  PASSED  ] 3 tests.
    [  FAILED  ] 1 test, listed below:
    [  FAILED  ] CHashTableTest.add2get

      可以看到,對于錯誤的CASE,會標出所在文件及其行數。

     如果我們需要輸出到XML文件,則執行./unittest --gtest_output=xml,那么會在當前目錄下生成test_detail.xml 文件,內容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <testsuites tests="3" failures="0" disabled="0" errors="0" time="0.001" name="AllTests">
      <testsuite name="CHashTableTest" tests="3" failures="0" disabled="0" errors="0" time="0.001">
        <testcase name="hashfunc" status="run" time="0.001" classname="CHashTableTest" />
        <testcase name="addget" status="run" time="0" classname="CHashTableTest" />
        <testcase name="delget" status="run" time="0" classname="CHashTableTest" />
      </testsuite>
    </testsuites>

      如此,一個簡單的單元測試寫完。因為太簡單,所以不需要使用google mock模擬一些依賴。后續我再寫結合google mock來寫一些復雜的gtest單元測試。

      下面來簡單說下gtest的工作流程。

      4、google test內部是如何執行我們的單元測試用例的

      首先從main函數看起。

      我們的main函數執行了RUN_ALL_TESTS宏,這個宏干了些什么事呢?

    #define RUN_ALL_TESTS()\
      (::testing::UnitTest::GetInstance()->Run())

    }  // namespace testing

      原來是調用了UnitTest靜態工廠實例的Run方法!在gtest里,一切測試用例都是Test類的實例!所以,Run方法將會執行所有的Test實例來運行所有的單元測試,看看類圖:

      為什么說一切單元測試用例都是Test類的實例呢?

      我們有兩種寫測試用例的方法,一種就是上面我說的TEST_F宏,這要求我們要顯示的定義一個子類繼承自Test類。在TEST_F宏里,會再次定義一個新類,繼承自我們上面定義的子類(兩重繼承哈)。

      第二種就是TEST宏,這個宏里不要求用戶代碼定義類,但在google test里,TEST宏還是定義了一個子類繼承自Test類。

      所以,UnitTest的Run方法只需要執行所有Test實例即可。

    個單元測試用例就是一個Test類子類的實例。它同時與TestResult,TestCase,TestInfo關聯起來,用于提供結果。

      當然,還有EventListen類來監控結果的輸出,控制測試的進度等。

      以上并沒有深入細節,只是大致幫助大家理解,我們寫的幾個簡單的gtest宏,和單元測試用例,到底是如何被執行的。接下來,我會通過gmock來深入的看看google單元測試的玩法。

    posted on 2013-08-28 10:39 順其自然EVO 閱讀(593) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    <2013年8月>
    28293031123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲AV无码成人精品区在线观看| 亚洲区日韩精品中文字幕| 亚洲高清视频免费| 亚洲色一区二区三区四区| 亚洲综合色在线观看亚洲| 亚洲精品免费观看| 精品久久久久久亚洲综合网| 亚洲AV无码精品无码麻豆| 成人午夜18免费看| 国产永久免费高清在线| 亚洲中文字幕无码爆乳| 亚洲精品无码成人片久久| 9久9久女女免费精品视频在线观看 | 成人在线免费观看| 中国性猛交xxxxx免费看| 亚洲久悠悠色悠在线播放| 精品亚洲一区二区三区在线观看| 99久久99这里只有免费费精品| 一区二区三区在线观看免费| 亚洲国产精品日韩在线| 伊人久久大香线蕉亚洲| 免费看的黄色大片| 精品一区二区三区免费毛片爱 | 成人免费无码大片a毛片| 玖玖在线免费视频| 免费的黄网站男人的天堂 | 未满十八私人高清免费影院| 亚洲fuli在线观看| 亚洲国产精品久久66| 亚洲AV蜜桃永久无码精品| 一个人免费观看在线视频www| 永久免费不卡在线观看黄网站| 美女免费视频一区二区三区| 亚洲人成人77777在线播放| 亚洲av综合avav中文| 亚洲国产精品一区二区第四页| 成人免费无码大片A毛片抽搐色欲| 日本在线看片免费| 三上悠亚电影全集免费| 一级女性全黄久久生活片免费| 亚洲av最新在线观看网址|