本文目的
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
