下載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));
};
