gmock使用、原理及源码分析
1 初识gmock
1.1 什么是Mock
便捷的模拟对象的方法。
1.2 Google Mock概述
google mock是用来配合google test对C++项目做单元测试的。它依赖于googletest
Google Mock(简称gmock)是Google在2008年推出的一套针对C++的Mock框架,它灵感取自于jMock、EasyMock、harcreat。它提供了以下这些特性:
- 轻松地创建mock类
- 支持丰富的匹配器(Matcher)和行为(Action)
- 支持有序、无序、部分有序的期望行为的定义
- 多平台的支持
1.3 获取、编译google mock
见gtest,gtest项目里就包含gmock
1.4 最简单的例子
class MockFoo: public FooInterface {
public:
MOCK_METHOD0(getArbitraryString, std::string());
};
using ::testing::Return;
int main(int argc, char** argv) {
::testing::InitGoogleMock(&argc, argv);
string value = "Hello World!";
MockFoo mockFoo;
EXPECT_CALL(mockFoo, getArbitraryString()).Times().
WillOnce(Return(value));
string returnValue = mockFoo.getArbitraryString();
cout << "Returned Value: " << returnValue << endl;
return EXIT_SUCCESS;
}
2 典型的流程
通过上述的例子,已经可以看出使用Mock类的一般流程如下:
- 引入你要用到的Google Mock名称. 除宏或其它特别提到的之外所有Google Mock名称都位于*testing*命名空间之下.
- 建立模拟对象(Mock Objects).
- 可选的,设置模拟对象的默认动作.
- 在模拟对象上设置你的预期(它们怎样被调用,应该怎样回应?).
2.1 自定义方法/成员函数的期望行为
在单元测试/主程序中使用这个Mock类中的方法时最关键的就是对期望行为的定义。
对方法期望行为的定义的语法格式如下:
EXPECT_CALL(mock_object, method(matcher1, matcher2, ...))
.With(multi_argument_matcher)
.Times(cardinality)
.InSequence(sequences)
.After(expectations)
.WillOnce(action)
.WillRepeatedly(action)
.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)的意思是缺省/重复行为。
先举个例子来说明一下,后面有针对更为详细的说明:
EXPECT_CALL(mockTurtle, getX()).Times(testing::AtLeast()).
WillOnce(testing::Return()).WillOnce(testing::Return()).
WillRepeatedly(testing::Return())
这个期望行为的定义的意思是:
- 调用mockTurtle的getX()方法
- 这个方法会至少调用5次
- 第一次被调用时返回100
- 第2次被调用时返回150
- 从第3次被调用开始每次都返回200
2.2 Matcher(匹配器)
Matcher用于定义Mock类中的方法的形参的值(当然,如果你的方法不需要形参时,可以保持match为空。),就是判断在调用这个函数时,入参的值是否符合预先设置的条件,就是一个预设的EXPECT_TRUE。
它有以下几种类型:
一般比较、浮点数的比较、字符串匹配、容器的匹配、成员匹配器、匹配函数或函数对象的返回值、指针匹配器、复合匹配器
具体参考原文吧https://www.cnblogs.com/welkinwalker/archive/2011/11/29/2267225.html
2.3 基数(Cardinalities)
基数用于Times()中来指定模拟函数将被调用多少次|
2.4 行为(Actions)
Actions(行为)用于指定Mock类的方法所期望模拟的行为:比如返回什么样的值、对引用、指针赋上怎么样个值,等等。 值的返回
|
Return() |
让Mock方法返回一个void结果 |
|
Return(value) |
返回值value |
|
ReturnNull() |
返回一个NULL指针 |
|
ReturnRef(variable) |
返回variable的引用. |
|
ReturnPointee(ptr) |
返回一个指向ptr的指针 |
另一面的作用(Side Effects)
|
Assign(&variable, value) |
将value分配给variable |
使用函数或者函数对象(Functor)作为行为
|
Invoke(f) |
使用模拟函数的参数调用f, 这里的f可以是全局/静态函数或函数对象. |
|
Invoke(object_pointer, &class::method) |
使用模拟函数的参数调用object_pointer对象的mothod方法. |
复合动作
|
DoAll(a1, a2, …, an) |
每次发动时执行a1到an的所有动作. |
|
IgnoreResult(a) |
执行动作a并忽略它的返回值. a不能返回void. |
复合行为举例:
EXPECT_CALL(mockIParameter, getParamter(testing::_, testing::_)).Times().\
WillOnce(testing::DoAll(testing::Assign(&a, b), testing::Return()));
2.5 序列(Sequences)
默认时,对于定义要的期望行为是无序(Unordered)的,但有时候我们需要定义有序的(Ordered)的调用方式,即序列 (Sequences) 指定预期的顺序. 在同一序列里的所有预期调用必须按它们指定的顺序发生; 反之则可以是任意顺序.
3 Google Mock Cookbook
3.1 Mock protected、private方法
Google Mock也可以模拟protected和private方法,比较神奇啊(其实从这点上也可以看出,Mock类不是简单地继承原本的接口,然后自己把它提供的方法实现;Mock类其实就等于原本的接口)。
对protected和private方法的Mock和public基本类似,只不过在Mock类中需要将这些方法设置成public。
3.2 Mock 模版类(Template Class)
Google Mock可以Mock模版类,只要在宏MOCK*的后面加上T。
4 Gmock原理及源码分析
4.1 基本原理
EXPECT_CALL.WillOnce的核心工作: untyped_actions_.push_back(new Action<F>(action)); 也就是说它将返回值塞进了一个vector容器中。
MOCK_METHOD0的核心工作:this->UntypedInvokeWith(&args))->GetValueAndDelete();也就是说它从之前说的那个vector中取出返回的结果被删除。
参见:单元测试Mock之c++ gmock实现原理 https://www.jianshu.com/p/06f0a7d85877
4.2 源码分析
参见:Google Mock(Gmock)简单使用和源码分析——源码分析 https://blog.csdn.net/breaksoftware/article/details/51438033
5 参考文档
转一篇小亮同学的google mock分享https://www.cnblogs.com/welkinwalker/archive/2011/11/29/2267225.html
单元测试Mock之c++ gmock实现原理 https://www.jianshu.com/p/06f0a7d85877
Google Mock(Gmock)简单使用和源码分析——源码分析 https://blog.csdn.net/breaksoftware/article/details/51438033
官网,但我今天打不开官网了。
gmock使用、原理及源码分析的更多相关文章
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- ConcurrentHashMap实现原理及源码分析
ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...
- HashMap和ConcurrentHashMap实现原理及源码分析
HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...
- (转)ReentrantLock实现原理及源码分析
背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...
- 【转】HashMap实现原理及源码分析
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景极其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...
- 【OpenCV】SIFT原理与源码分析:DoG尺度空间构造
原文地址:http://blog.csdn.net/xiaowei_cqu/article/details/8067881 尺度空间理论 自然界中的物体随着观测尺度不同有不同的表现形态.例如我们形 ...
- 《深入探索Netty原理及源码分析》文集小结
<深入探索Netty原理及源码分析>文集小结 https://www.jianshu.com/p/239a196152de
- HashMap实现原理及源码分析之JDK8
继续上回HashMap的学习 HashMap实现原理及源码分析之JDK7 转载 Java8源码-HashMap 基于JDK8的HashMap源码解析 [jdk1.8]HashMap源码分析 一.H ...
- 【OpenCV】SIFT原理与源码分析:关键点描述
<SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 由前一篇<方向赋值>,为找到的关键点即SI ...
随机推荐
- Request笔记
1 Request 的简介和运行环境 1.HttpServletRequest 概述 我们在创建 Servlet 时会覆盖 service()方法,或 doGet()/doPost(),这些方法都有两 ...
- 我是怎么一步步用go找出压测性能瓶颈
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由mariolu 发表于云+社区专栏 序言: 笔者要在线上服务器load日志并且重放来测一些机器性能指标.模拟机器资源比较少,相对的 ...
- addEventListener()和removeEventListener()
作用: addEventListener()与removeEventListener()用于处理指定和删除事件处理程序操作. 它们都接受3个参数:事件名.事件处理的函数和布尔值. 布尔值参数是true ...
- 推荐系统(Recommender System)
推荐系统(Recommender System) 案例 为用户推荐电影 数据展示 Bob Tom Alice Jack 动作成分 浪漫成分 Movie1 5 ? 0 3 ? ? Movie2 ? 0 ...
- solr的schema.xml配置文件关键词意义
fieldType:配置扩展的分析器analyzer:具体的分析器的全路径field:配置具体的索引业务字段name:字段的名称type:指定使用哪种分析器域:StringField,textFiel ...
- tomcat 修改 编码
<Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080" ...
- 获取用户Ip地址通用方法常见安全隐患(HTTP_X_FORWARDED_FOR)
分析过程 这个来自一些项目中,获取用户Ip,进行用户操作行为的记录,是常见并且经常使用的. 一般朋友,都会看到如下通用获取IP地址方法. function getIP() { if (isset($_ ...
- 修改npm包管理器的registry为淘宝镜像(npm.taobao.org)<转>
起因 安装了node,安装了npm之后,官方的源实在是 太慢了! 看了看淘宝的npm镜像, http://npm.taobao.org/ 竟然说让我再下载一个cnpm,要不然就每次都得install ...
- Eclipse 入手配置
工欲善其事,必先利其器 在安装eclipse后进行简单的配置能够为以后的开发提高不少效率,这里慢慢先记录自己的经验. 一.编码配置 utf-8 1.worksplace: 首先设置就是workspac ...
- equals()重写
** 注意 ** 1.重写equals方法修饰符必须是public,因为是重写的Object的方法. 2.参数类型必须是Object. 3.重写equals方法后最好重写hashCode方法,否则两个 ...