google mock分享(全网最全最好的gmock文档,没有之一)
- EXPECT_CALL(mockFoo, getValue()).WillOnce(Return(string("Hello World")));
但有时候我们需要定义有序的(Ordered)的调用方式,即序列 (Sequences) 指定预期的顺序. 在同一序列里的所有预期调用必须按它们指定的顺序发生; 反之则可以是任意顺序.
- using ::testing::Return;
- using ::testing::Sequence;
- int main(int argc, char **argv) {
- ::testing::InitGoogleMock(&argc, argv);
- Sequence s1, s2;
- MockFoo mockFoo;
- EXPECT_CALL(mockFoo, getSize()).InSequence(s1, s2).WillOnce(Return(1));
- EXPECT_CALL(mockFoo, getValue()).InSequence(s1).WillOnce(Return(
- string("Hello World!")));
- cout << "First:\t" << mockFoo.getSize() << endl;
- cout << "Second:\t" << mockFoo.getValue() << endl;
- return EXIT_SUCCESS;
- }
- 首先在第8行建立两个序列:s1、s2。
- 然后在第11行中,EXPECT_CALL(mockFoo, getSize()).InSequence(s1, s2)说明getSize()的行为优先于s1、s2.
- 而第12行时,EXPECT_CALL(mockFoo, getValue()).InSequence(s1)说明getValue()的行为在序列s1中。
得到的结果如下:
Second: Hello World!
当我尝试一下把mockFoo.getSize()和mockFoo.getValue()的调用对调时试试:
- cout << "Second:\t" << mockFoo.getValue() << endl;
- cout << "First:\t" << mockFoo.getSize() << endl;
Unexpected mock function call – returning default value.
Function call: getValue()
Returns: ""
Google Mock tried the following 1 expectation, but it didn't match:
FooMain.cc:29: EXPECT_CALL(mockFoo, getValue())…
Expected: all pre-requisites are satisfied
Actual: the following immediate pre-requisites are not satisfied:
FooMain.cc:28: pre-requisite #0
(end of pre-requisites)
Expected: to be called once
Actual: never called – unsatisfied and active
Second:
First: 1
FooMain.cc:29: Failure
Actual function call count doesn't match EXPECT_CALL(mockFoo, getValue())…
Expected: to be called once
Actual: never called – unsatisfied and active
另外,我们还有一个偷懒的方法,就是不要这么傻乎乎地定义这些个Sequence s1, s2的序列,而根据我定义期望行为(EXPECT_CALL)的顺序而自动地识别调用顺序,这种方式可能更为地通用。
- using ::testing::InSequence;
- using ::testing::Return;
- int main(int argc, char **argv) {
- ::testing::InitGoogleMock(&argc, argv);
- InSequence dummy;
- MockFoo mockFoo;
- EXPECT_CALL(mockFoo, getSize()).WillOnce(Return(1));
- EXPECT_CALL(mockFoo, getValue()).WillOnce(Return(string("Hello World")));
- cout << "First:\t" << mockFoo.getSize() << endl;
- cout << "Second:\t" << mockFoo.getValue() << endl;
- return EXIT_SUCCESS;
- }
Mock实践
下面我从我在工作中参与的项目中选取了一个实际的例子来实践Mock。
这个例子的背景是用于搜索引擎的:
- 引擎接收一个查询的Query,比如http://127.0.0.1/search?q=mp3&retailwholesale=0&isuse_alipay=1
- 引擎接收到这个Query后,将解析这个Query,将Query的Segment(如q=mp3、retail_wholesale=0放到一个数据结构中)
- 引擎会调用另外内部模块具体根据这些Segment来处理相应的业务逻辑。
由于Google Mock不能Mock模版方法,因此我稍微更改了一下原本的接口,以便演示:
我改过的例子
我们先来看看引擎定义好的接口们:
VariantField.h 一个联合体,用于保存Query中的Segment的值
- #ifndef VARIANTFIELD_H_
- #define VARIANTFIELD_H_
- #include <boost/cstdint.hpp>
- namespace seamless {
- union VariantField
- {
- const char * strVal;
- int32_t intVal;
- };
- } // namespace mlr_isearch_api
- #endif // VARIANTFIELD_H_
IParameterInterface.h 提供一个接口,用于得到Query中的各个Segment的值
- #ifndef IPARAMETERINTERFACE_H_
- #define IPARAMETERINTERFACE_H_
- #include <boost/cstdint.hpp>
- #include "VariantField.h"
- namespace seamless {
- class IParameterInterface {
- public:
- virtual ~IParameterInterface() {};
- public:
- virtual int32_t getParameter(const char* name, VariantField*& value) = 0;
- };
- } // namespace
- #endif // IPARAMETERINTERFACE_H_
IAPIProviderInterface.h 一个统一的外部接口
- #ifndef IAPIPROVIDERINTERFACE_H_
- #define IAPIPROVIDERINTERFACE_H_
- #include <boost/cstdint.hpp>
- #include "IParameterInterface.h"
- #include "VariantField.h"
- namespace seamless {
- class IAPIProviderInterface {
- public:
- IAPIProviderInterface() {}
- virtual ~IAPIProviderInterface() {}
- public:
- virtual IParameterInterface* getParameterInterface() = 0;
- };
- }
- #endif // IAPIPROVIDERINTERFACE_H_
引擎定义好的接口就以上三个,下面是引擎中的一个模块用于根据Query中的Segment接合业务处理的。Rank.h 头文件
- #ifndef RANK_H_
- #define RANK_H_
- #include "IAPIProviderInterface.h"
- namespace seamless {
- class Rank {
- public:
- virtual ~Rank() {}
- public:
- void processQuery(IAPIProviderInterface* iAPIProvider);
- };
- } // namespace seamless
- #endif // RANK_H_
Rank.cc 实现
- #include <cstdlib>
- #include <cstring>
- #include <iostream>
- #include <string>
- #include "IAPIProviderInterface.h"
- #include "IParameterInterface.h"
- #include "VariantField.h"
- #include "Rank.h"
- using namespace seamless;
- using namespace std;
- namespace seamless {
- void Rank::processQuery(IAPIProviderInterface* iAPIProvider) {
- IParameterInterface* iParameter = iAPIProvider->getParameterInterface();
- if (!iParameter) {
- cerr << "iParameter is NULL" << endl;
- return;
- }
- int32_t isRetailWholesale = 0;
- int32_t isUseAlipay = 0;
- VariantField* value = new VariantField;
- iParameter->getParameter("retail_wholesale", value);
- isRetailWholesale = (strcmp(value->strVal, "0")) ? 1 : 0;
- iParameter->getParameter("is_use_alipay", value);
- isUseAlipay = (strcmp(value->strVal, "0")) ? 1 : 0;
- cout << "isRetailWholesale:\t" << isRetailWholesale << endl;
- cout << "isUseAlipay:\t" << isUseAlipay << endl;
- delete value;
- delete iParameter;
- }
- } // namespace seamless
- 从上面的例子中可以看出,引擎会传入一个IAPIProviderInterface对象,这个对象调用getParameterInterface()方法来得到Query中的Segment。
- 因此,我们需要Mock的对象也比较清楚了,就是要模拟引擎将Query的Segment传给这个模块。其实就是让=模拟iParameter->getParameter方法:我想让它返回什么样的值就返回什么样的值.
下面我们开始Mock了:
MockIParameterInterface.h 模拟模拟IParameterInterface类
- #ifndef MOCKIPARAMETERINTERFACE_H_
- #define MOCKIPARAMETERINTERFACE_H_
- #include <boost/cstdint.hpp>
- #include <gmock/gmock.h>
- #include "IParameterInterface.h"
- #include "VariantField.h"
- namespace seamless {
- class MockIParameterInterface: public IParameterInterface {
- public:
- MOCK_METHOD2(getParameter, int32_t(const char* name, VariantField*& value));
- };
- } // namespace seamless
- #endif // MOCKIPARAMETERINTERFACE_H_
MockIAPIProviderInterface.h 模拟IAPIProviderInterface类
- #ifndef MOCKIAPIPROVIDERINTERFACE_H_
- #define MOCKIAPIPROVIDERINTERFACE_H_
- #include <gmock/gmock.h>
- #include "IAPIProviderInterface.h"
- #include "IParameterInterface.h"
- namespace seamless {
- class MockIAPIProviderInterface: public IAPIProviderInterface{
- public:
- MOCK_METHOD0(getParameterInterface, IParameterInterface*());
- };
- } // namespace seamless
- #endif // MOCKIAPIPROVIDERINTERFACE_H_
tester.cc