something about Google Mock / gmock使用小結


下載gmock:http://code.google.com/p/googlemock/downloads/list

安裝:將下載的壓縮包解壓出來,到解壓目錄下執行:

./configure

然后執行:

make

注意,這個make不會編譯Google Mock自己的測試用例。要編譯它們,需要到解壓目錄下的“make”子目錄下,執行:

make gmock_test

文章來源:http://www.codelast.com/

然后就會看到該目錄下生成了一個可執行文件 gmock_test ,執行這個可執行文件,就可以看到Google Mock測試用例的執行結果(應該是成功的,如果有失敗,則應修改Makefile使之成功):

Running main() from gmock_main.cc

[==========] Running 13 tests from 3 test cases.

[----------] Global test environment set-up.

[----------] 6 tests from InitGoogleMockTest

[ RUN      ] InitGoogleMockTest.ParsesInvalidCommandLine

[       OK ] InitGoogleMockTest.ParsesInvalidCommandLine (0 ms)

[ RUN      ] InitGoogleMockTest.ParsesEmptyCommandLine

[       OK ] InitGoogleMockTest.ParsesEmptyCommandLine (0 ms)

[ RUN      ] InitGoogleMockTest.ParsesSingleFlag

[       OK ] InitGoogleMockTest.ParsesSingleFlag (0 ms)

[ RUN      ] InitGoogleMockTest.ParsesUnrecognizedFlag

[       OK ] InitGoogleMockTest.ParsesUnrecognizedFlag (0 ms)

[ RUN      ] InitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag

[       OK ] InitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag (0 ms)

[ RUN      ] InitGoogleMockTest.CallsInitGoogleTest

[       OK ] InitGoogleMockTest.CallsInitGoogleTest (0 ms)

[----------] 6 tests from InitGoogleMockTest (1 ms total)

[----------] 6 tests from WideInitGoogleMockTest

[ RUN      ] WideInitGoogleMockTest.ParsesInvalidCommandLine

[       OK ] WideInitGoogleMockTest.ParsesInvalidCommandLine (0 ms)

[ RUN      ] WideInitGoogleMockTest.ParsesEmptyCommandLine

[       OK ] WideInitGoogleMockTest.ParsesEmptyCommandLine (0 ms)

[ RUN      ] WideInitGoogleMockTest.ParsesSingleFlag

[       OK ] WideInitGoogleMockTest.ParsesSingleFlag (0 ms)

[ RUN      ] WideInitGoogleMockTest.ParsesUnrecognizedFlag

[       OK ] WideInitGoogleMockTest.ParsesUnrecognizedFlag (0 ms)

[ RUN      ] WideInitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag

[       OK ] WideInitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag (0 ms)

[ RUN      ] WideInitGoogleMockTest.CallsInitGoogleTest

[       OK ] WideInitGoogleMockTest.CallsInitGoogleTest (0 ms)

[----------] 6 tests from WideInitGoogleMockTest (0 ms total)

[----------] 1 test from FlagTest

[ RUN      ] FlagTest.IsAccessibleInCode

[       OK ] FlagTest.IsAccessibleInCode (0 ms)

[----------] 1 test from FlagTest (0 ms total)

[----------] Global test environment tear-down

[==========] 13 tests from 3 test cases ran. (1 ms total)

[  PASSED  ] 13 tests.

文章來源:http://www.codelast.com/

其他記錄:

(1)Google Mock對象在析構的時候會檢查mock函數的執行結果是否與預期相符,如果mock對象一直存在,最終的檢查就不會發生。因此,如果你在堆(heap)中創建mock對象的話,最好使用內存泄漏檢查工具來確定你的test是否做好了mock對象銷毀工作。

(2)Google Mock要求在調用mock函數之前設置好預期的結果,否則其行為就是“未定義”的。

(3)使用EXPECT_CALL() 宏來設置一個mock函數調用的預期結果。其語法為:

EXPECT_CALL(mock_object, method(matchers))

.Times(cardinality)

.WillOnce(action)

.WillRepeatedly(action);

第一個參數是mock對象,第二個參數是mock函數名及其參數。二者中間是以逗號(而不是點號)分隔的,至於為什么是這樣,回答只有一個:技術原因。

宏后面還可以緊跟若干語句,以提供對mock函數調用的預期結果的更多信息。這種風格的語法被一些人稱作是“特定領域語言”(Domain-Specific Language,DSL)。

(4)Google Mock中有一些可能初次見到時感覺比較陌生的概念,例如 matcher,cardinality,etc.  這些概念在gmock的手冊中都有詳細說明,網上也可以找到一些中文文檔,為了能真正用起來gmock,一定要看清了這些概念的含義。

(5)一個返回值為 bool 類型的mock函數默認是返回 false 的!所以,如果你沒有設置函數的默認返回值,你的test函數被調用了之后很可能只執行了一部分(例如,你的test函數調用了一個mock函數,而該函數在返回 false 時,將不再繼續執行其后的代碼),這樣你的test將不能覆蓋某函數的全部代碼,而這並不是你樂見的,切記。

(6)在mock對象析構時,對“期望”的檢驗才會被執行,所以,如果你的mock對象一直沒有析構(例如,你在堆中創建了一個mock對象,卻忘了刪除它 。有人說可以用內存檢查工具來防止這一點,但是要知道沒有工具是可以保證100%可靠的),則檢驗一直不會被執行。如果你擔心這種情況,就可以主動進行檢驗:

Mock::VerifyAndClearExpectations(&mock_object):

該方法返回一個bool值,以顯示檢驗是否成功(true代表成功)。所以,你可以把它嵌套在EXPECT_TRUE()或者ASSERT_TRUE()里面來測試檢驗結果。

文章來源:http://www.codelast.com/

(7)gmock安裝包解壓目錄下的“scripts”子目錄下,有一個Python腳本fuse_gmock_files.py,這個腳本一般用不到,它是用來合並Google Mock的文件的。Google Mock包含N多文件,如果你要自己擴充它的功能,那么你就需要自行修改某些文件的源碼,如果你把Google Mock拷貝到另一台計算機上,從頭開始修改很多個文件的源碼可能就很麻煩,所以腳本fuse_gmock_files.py就可以將Google Mock原來的N多文件合並為三個文件:gtest/gtest.h,gmock/gmock.h 和 gmock-gtest-all.cc。這樣的話就方便多了。

(8)Google Mock有三個(主要的)指導文檔,其難度由低到高分別為:ForDummies,CheatSheet,CookBook。所以,如果你剛接觸gmock,應該按這個順序依次學習那三個文檔。

(9)對普通函數,使用宏 MOCK_METHODn 來定義一個模擬函數,其中n是你要模擬的函數的參數的個數,例如,你要模擬的函數沒有參數,則應使用 MOCK_METHOD0。對const函數,你就要改用宏 MOCK_CONST_METHODn 來定義。

(10)static/靜態 函數如何mock?

在Google Mock的官方“常見問題”的回答中(請點擊這個鏈接,在文章中搜索“static”即可定位到),Google是這樣說的:You can, but you need to make some changes(可以,但是你需要做一些修改).Google說,如果你需要mock一個靜態函數,那說明你的程序模塊過於“緊耦合”了(並且靈活性不夠、重用性不夠、可測試性不夠),你最好是定義一個小接口,通過這個接口來調用那個函數,然后就容易mock了。

這就是Google Mock給出的答案,至於你怎么想的,又會不會按它的建議去做,決定權就在你自己了。

(11)使用 ON_CALL() 宏可以設定mocker函數的返回值,例如以下代碼:

  

ON_CALL(myMockObj, myFunc())

    .WillByDefault(Return(123));

表示“命令”函數 myFunc() 的返回值為 123,其中 myMockObj 是mocker對象,函數 myFunc() 是在該mocker類中定義的模擬函數。可見,有了Goolge Mock這樣的工具,我們就可以隨意“控制”一個函數的行為,讓它返回我們想要返回的值,從而可以使得單元測試可以按我們的意願來進行——有時候,你必須要這么做,例如,你的一個函數 myInvoker() 調用了 myFunc() 函數,而myFunc() 函數的返回值是根據當前時間而變化的,因此其返回值不定,我們無法使其返回一個固定的值,從而我們在對 myInvoker() 做單元測試的時候,就“很難測”了,這個時候,我們就要命令 myFunc() 永遠返回我們想要的值,從而可以使得對 myInvoker() 的單元測試可以順利進行。

多么妙的想法!這就是mock的巨大作用,盡管它只是一個后台的“模仿者”(mocker),但是它產生的作用,卻是真真切切的。

文章來源:http://www.codelast.com/

(12)編譯你自己的單元測試的時候遇到“undefined reference to `vtable for XXX”,“undefined reference to `typeinfo for XXX'”錯誤?

出現這個錯誤,我可以提醒你的一點是:檢查你的mocker類中,是否按照gmock文檔的要求,把某些函數定義成純虛函數了。比如我有一個tobe mocked的類:

class CTobeMocked

{

public:

    CTobeMocked() {}

    virtual ~CTobeMocked() {}

public:

    virtual double myFunc(const string &str) = 0;

};

這個類就是要被mock的類,注意里面的函數myFunc()是被定義成純虛函數的,如果你漏了后面的“ = 0”,那么你編寫了相應的mocker類之后,編譯的時候就會出錯。

我的mocker類如下:

class CMyMocker : public CTobeMocked

{

public:

    CMyMocker() {}

    virtual ~CMyMocker() {}

public:

    MOCK_METHOD(myFunc, double(const string &str));

};


免責聲明!

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



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