google mock分享(全网最全最好的gmock文档,没有之一)

转载
Content

Google Mock 入门

概述

什么是Mock?

Mock,更确切地说应该是Mock Object。它究竟是什么?它有什么作用?在这里,我也只能先说说我的理解。 比如当我们在单元测试、模块的接口测试时,当这个模块需要依赖另外一个/几个类,而这时这些个类还没有开发好(那名开发同学比较懒,呵呵),这时我们就可以定义了Mock对象来模拟那些类的行为。
说得更直白一些,就是自己实现一个假的依赖类,对这个类的方法你想要什么行为就可以有什么行为,你想让这个方法返回什么结果就可以返回怎么样的结果。
但这时很多同学往往会提出一个问题:"那既然是我自己实现一个假的依赖类",那和那些市面上的Mock框架有什么关系啊?
这个其实是这样的,这些个Mock框架可以帮助你比较方便、比较轻松地实现这些个假的依赖类。毕竟,如果你实现这么一个假的依赖类的时间花费过场的话,那我还不如等待那位懒惰的同学吧。

Google Mock概述

Google Mock(简称gmock)是Google在2008年推出的一套针对C++的Mock框架,它灵感取自于jMockEasyMockharcreat。它提供了以下这些特性:

参考文档

Google Mock使用

最简单的例子

我比较喜欢举例来说明这些个、那些个玩意,因此我们先来看看Google Mock就简单的用法和作用。

FooInterface.h


  1. #ifndef FOOINTERFACE_H_
  2. #define FOOINTERFACE_H_
  3. #include <string>
  4. namespace seamless {
  5. class FooInterface {
  6. public:
  7. virtual ~FooInterface() {}
  8. public:
  9. virtual std::string getArbitraryString() = 0;
  10. };
  11. } // namespace seamless
  12. #endif // FOOINTERFACE_H_
这里需要注意几点:

  • FooInterface的析构函数~FooInterface()必须是virtual的
  • 在第13行,我们得把getArbitraryString定义为纯虚函数。其实getArbitraryString()也不一定得是纯虚函数,这点我们后面会提到.

现在我们用Google Mock来定义Mock类 FooMock.h


  1. #ifndef MOCKFOO_H_
  2. #define MOCKFOO_H_
  3. #include <gmock/gmock.h>
  4. #include <string>
  5. #include "FooInterface.h"
  6. namespace seamless {
  7. class MockFoo: public FooInterface {
  8. public:
  9. MOCK_METHOD0(getArbitraryString, std::string());
  10. };
  11. } // namespace seamless
  12. #endif // MOCKFOO_H_
我们稍微来解释一下这个Mock类的定义:

  • 第10行我们的MockFoo类继承懒同学的FooInterface
  • 第22行我们定义使用gmock中的一个宏(Macro)MOCK_METHOD0来定义MockFoo中的getArbitraryString。Google Mock是需要你根据不同的形参个数来使用不同的Mock Method,我这里getArbitraryString没有函数,就是MOCK_METHOD0了,同理,如果是一个形参,就是MOCK_METHOD1了,以此往下。

FooMain.cc


  1. #include <cstdlib>
  2. #include <gmock/gmock.h>
  3. #include <gtest/gtest.h>
  4. #include <iostream>
  5. #include <string>
  6. #include "MockFoo.h"
  7. using namespace seamless;
  8. using namespace std;
  9. using ::testing::Return;
  10. int main(int argc, char** argv) {
  11. ::testing::InitGoogleMock(&argc, argv);
  12. string value = "Hello World!";
  13. MockFoo mockFoo;
  14. EXPECT_CALL(mockFoo, getArbitraryString()).Times(1).
  15. WillOnce(Return(value));
  16. string returnValue = mockFoo.getArbitraryString();
  17. cout << "Returned Value: " << returnValue << endl;
  18. return EXIT_SUCCESS;
  19. }

最后我们运行编译,得到的结果如下:

Returned Value: Hello World!

在这里:

  • 第15行,初始化一个Google Mock
  • 第18行,声明一个MockFoo的对象:mockFoo
  • 第19行,是为MockFoo的getArbitraryString()方法定义一个期望行为,其中Times(1)的意思是运行一次,WillOnce(Return(value))的意思是第一次运行时把value作为getArbitraryString()方法的返回值。

这就是我们最简单的使用Google Mock的例子了,使用起来的确比较简便吧。

典型的流程

通过上述的例子,已经可以看出使用Mock类的一般流程如下:

自定义方法/成员函数的期望行为

从上述的例子中可以看出,当我们针对懒同学的接口定义好了Mock类后,在单元测试/主程序中使用这个Mock类中的方法时最关键的就是对期望行为的定义。
对方法期望行为的定义的语法格式如下:


  1. EXPECT_CALL(mock_object, method(matcher1, matcher2, ...))
  2. .With(multi_argument_matcher)
  3. .Times(cardinality)
  4. .InSequence(sequences)
  5. .After(expectations)
  6. .WillOnce(action)
  7. .WillRepeatedly(action)
  8. .RetiresOnSaturation();
解释一下这些参数(虽然很多我也没弄明白):

  • 第1行的mock_object就是你的Mock类的对象
  • 第1行的method(matcher1, matcher2, …)中的method就是你Mock类中的某个方法名,比如上述的getArbitraryString;而matcher(匹配器)的意思是定义方法参数的类型,我们待会详细介绍。
  • 第3行的Times(cardinality)的意思是之前定义的method运行几次。至于cardinality的定义,我也会在后面详细介绍。
  • 第4行的InSequence(sequences)的意思是定义这个方法被执行顺序(优先级),我会再后面举例说明。
  • 第6行WillOnce(action)是定义一次调用时所产生的行为,比如定义该方法返回怎么样的值等等。
  • 第7行WillRepeatedly(action)的意思是缺省/重复行为。

我稍微先举个例子来说明一下,后面有针对更为详细的说明:


  1. EXPECT_CALL(mockTurtle, getX()).Times(testing::AtLeast(5)).
  2. WillOnce(testing::Return(100)).WillOnce(testing::Return(150)).
  3. WillRepeatedly(testing::Return(200))
这个期望行为的定义的意思是:

  • 调用mockTurtle的getX()方法
  • 这个方法会至少调用5次
  • 第一次被调用时返回100
  • 第2次被调用时返回150
  • 从第3次被调用开始每次都返回200

Matcher(匹配器)

Matcher用于定义Mock类中的方法的形参的值(当然,如果你的方法不需要形参时,可以保持match为空。),它有以下几种类型:(更详细的介绍可以参见Google Mock Wiki上的Matcher介绍
通配符

_ 可以代表任意类型
A() or An() 可以是type类型的任意值
这里的_和*A*包括下面的那个匹配符都在Google Mock的*::testing*这个命名空间下,大家要用时需要先引入那个命名空间

一般比较

Eq(value) 或者 value argument == value,method中的形参必须是value
Ge(value) argument >= value,method中的形参必须大于等于value
Gt(value) argument > value
Le(value) argument <= value
Lt(value) argument < value
Ne(value) argument != value
IsNull() method的形参必须是NULL指针
NotNull() argument is a non-null pointer
Ref(variable) 形参是variable的引用
TypedEq(value) 形参的类型必须是type类型,而且值必须是value

浮点数的比较

DoubleEq(a_double) 形参是一个double类型,比如值近似于a_double,两个NaN是不相等的
FloatEq(a_float) 同上,只不过类型是float
NanSensitiveDoubleEq(a_double) 形参是一个double类型,比如值近似于a_double,两个NaN是相等的,这个是用户所希望的方式
NanSensitiveFloatEq(a_float) 同上,只不过形参是float

字符串匹配
这里的字符串即可以是C风格的字符串,也可以是C++风格的。

ContainsRegex(string) 形参匹配给定的正则表达式
EndsWith(suffix) 形参以suffix截尾
HasSubstr(string) 形参有string这个子串
MatchesRegex(string) 从第一个字符到最后一个字符都完全匹配给定的正则表达式.
StartsWith(prefix) 形参以prefix开始
StrCaseEq(string) 参数等于string,并且忽略大小写
StrCaseNe(string) 参数不是string,并且忽略大小写
StrEq(string) 参数等于string
(1/5)上一页 下一页| 剩余全文

分享到:
  网友评论(0)
 
回到顶部