本文目的
gmock框架中自帶Matcher只針對c++內置類型,如string,int,float等等,有時候無法滿足項目要求,所以需要編寫自己的Matcher對象。本文介紹如何使用gmock提供的Matcher宏快速編寫自己的Matcher對象。
在測試重載的mock函數時,需要對Matcher做特別的封裝,否則編譯在查找重載函數時會出現歧義。
待測的對象
/* * 文件Base.h * * Created on: 2011-10-1 * Author: bourneli */ #ifndef BASE_H_ #define BASE_H_ #include <iostream> #include <string> using namespace std; class Param { public: int n1; double f1; }; class Dependence { public: virtual ~Dependence(){} virtual void show() const { cout << "I am a dependence of Foo" << endl; } virtual void show(const string& sSth) const { cout << "show: " << sSth << endl; } virtual void show(const Param& oParam) const { cout << oParam.n1 << endl; cout << oParam.f1 << endl; } }; /* * 調用mock的對象 */ class Foo { public: void showVoid(const Dependence& oDep)const { oDep.show(); } void showString(const Dependence& oDep, const string& sSth)const { oDep.show(sSth); } void showParam(const Dependence& oDep, const Param& oParam)const { oDep.show(oParam); } }; #endif /* BASE_H_ */
類Dependece有三個重載函數:
- void show(void)
- void show(const string&)
- void show(const Param&)
需要編寫Dependence的Mock對象,用於測試類Foo,類Foo也分別有三個方法調用類Dependence不同的重載方法:
- void showVoid(const Dependence&) --- 調用Dependence::show(void)
- void showString(const Dependence&, const string&) --- 調用Dependence::show(const string&)
- void showParam(const Dependence&, const Param&) --- 調用Dependence::show(const Param&)
還有一個類Param,這是一個自定義類,需要自己編寫Param的Matcher對象。在這里,匹配邏輯為:如果兩個Param對象的n1屬性相同,那么就匹配。
編寫自己的Matcher
編寫自己的Matcher對象在gmock1.4后變得很容易,gmock框架為我們做了大部分的事情,看看如下的代碼:
// custom matcher MATCHER_P(ParamObjMatcher, oParam, "") { const Param& op = (const Param&)arg; return op.n1 == oParam.n1; }
只用了兩行代碼,就完成了自定義Matcher。MATCHER_P中的P代表參數,MATCHER_P其實應該寫成“MATCHER_P1”,表示該matcher的構造函數只接受一個參數,同樣的還有“MATCHER_P2、MATCHER_P3,..., MATCHER_P10”。宏的第一個參數代表該Matcher的類名,第二個參數代表Matcher的構造函數中的第一個參數,最后一個空內容的字符代表失敗時輸出信息,為空那么gmock會默認為你填寫相關信息。arg是這個宏中的一個參數,代表被匹配的對象,在這里也就是“cosnt Param&”。Dependence類的mock對象如下,詳細信息可以參見文章《gmock學習01---Linux配置gmock》。
/* * 文件Dependence_mock.h * * Created on: 2011-10-1 * Author: bourneli */ #ifndef DEPENDENCE_MOCK_H_ #define DEPENDENCE_MOCK_H_ #include <string> #include "gmock/gmock.h" #include "Base.h" // mock class class DependenceMock: public Dependence { public: MOCK_CONST_METHOD0(show, void()); MOCK_CONST_METHOD1(show, void(const string&)); MOCK_CONST_METHOD1(show, void(const Param&)); }; // custom matcher MATCHER_P(ParamObjMatcher, oParam, "") { const Param& op = (const Param&)arg; return op.n1 == oParam.n1; } #endif /* DEPENDENCE_MOCK_H_ */
編寫測試用例
mock的相關工作完成后,可以編寫測試用例,首先看看測試用例的源代碼,如下:
/* * 文件DependenceUT.cpp * * Created on: 2011-10-1 * Author: bourneli */ #include "gtest/gtest.h" #include "gmock/gmock.h" #include "Dependence_mock.h" #include "Base.h" using ::testing::MatchesRegex; using ::testing::Matcher; TEST(DependenceTestSuite, ShowVoidTestCase) { DependenceMock oMock; EXPECT_CALL(oMock, show()); Foo oFoo; oFoo.showVoid(oMock); } TEST(DependenceTestSuite, ShowStringTestCase) { DependenceMock oMock; EXPECT_CALL(oMock, show(Matcher<const string&> // 注意這里
(MatchesRegex(".*error.*")))); Foo oFoo; oFoo.showString(oMock, "error happened in log"); } TEST(DependenceTestSuite, ShowParamTestCase) { DependenceMock oMock; Param op; op.n1 = 1; op.f1 = 0.1; EXPECT_CALL(oMock, show(Matcher<const Param&> // 注意這里 (ParamObjMatcher(op)))); Foo oFoo; op.f1 = 0.2; // 沒有任何影響,因為只比較n1 oFoo.showParam(oMock, op); }
上面特別需要注意的地方是標有“注意這里”注釋的代碼,意義在於標記出該Matcher對象對應的類,這樣編譯器就可以根據類找到特定的重載函數。比如,MatchesRegex這個Matcher對象被Matcher<const string&>封裝后,編譯器就知道是調用void show(const string&)這個重載函數,同理對應我們的自定義Matcher ParamObjMatcher。這里還有一個小技巧,你可以在自定義Matcher中使用GTEST的相關斷言,這樣可以方便的驗證自定義對象中的值。
結論
- 使用宏MATCHER_P快速編寫自己的Matcher對象。
- 使用Matcher<T>指定Matcher對象對應的類型,告知編譯器如何在重載函數查找特定的函數。
- 在自定義Matcher中使用gtest斷言,可以方便驗證mock函數的輸入否和期望。
相關資料
- Selecting Between Overloaded Functions http://code.google.com/p/googlemock/wiki/CookBook#Selecting_Between_Overloaded_Functions
- GMock Build-In Matchers http://code.google.com/p/googlemock/wiki/CheatSheet#Matchers