Google Mock(Gmock)简单使用和源码分析——简单使用
初识Gmock是之前分析GTest源码时,它的源码和GTest源码在同一个代码仓库中(https://github.com/google/googletest)。本文我将以目前最新的Gmock1.7版本为范例,分析其实现原理。(转载请指明出于breaksoftware的csdn博客)
Gmock是google开发的一套辅助测试的工具,它往往和GTest结合在一起使用。在实际工作中,一个人不可能完成整条线的开发工作。于是我们会在约定接口的前提下,各自完成各自的模块。自己的模块开发完之后,我们需要自测。但是这个时候别人的模块可能还没完成,那么我们就需要模拟约定的接口进行自测。Gmock就是一个强大的模拟接口的工具。
使用方法
首先我们讲解一下其主要的使用方法。目前网络上有一篇写的不错的使用说明《转一篇小亮同学的google mock分享》,如果大家想了解其详细的使用方法,可以参阅这篇文章。如果只是想简单的了解其使用并理解其实现原理,可以先参阅本文。
我们假设一个支付场景逻辑开发业务。我们开发复杂的业务模块,而团队其他成员开发用户行为模块。他们和我们约定了如下接口
class User {
public:User() {};~User() {};
public:// 登录virtual bool Login(const std::string& username, const std::string& password) = 0;// 支付virtual bool Pay(int money) = 0;// 是否登录virtual bool Online() = 0;
};
我们的业务模块要让用户登录,并发起支付行为。于是我们的代码如下
class Biz {
public:void SetUser(User* user) {_user = user;}std::string pay(const std::string& username, const std::string& password, int money) {std::string ret;if (!_user) {ret = "pointer is null.";return ret;}if (!_user->Online()) {ret = "logout status.";// 尚未登录,要求登录if (!_user->Login(username, password)) {// 登录失败ret += "login error.";return ret;} else {// 登录成功ret += "login success.";}} else {// 已登录ret = "login.status";}if (!_user->Pay(money)) {ret += "pay error.";} else {ret += "pay success.";}return ret;}private:User* _user;
};
这段逻辑的口语描述就是:我们先看看用户登录了没,如果没有登录则要求用户登录。如果登录失败,则直接返回;如果登录成功,则执行支付行为。最后将流程的状态输出。
那我们如何使用Gmock辅助测试呢?
第一步我们需要Mock接口类
class TestUser : public User {
public:MOCK_METHOD2(Login, bool(const std::string&, const std::string&));MOCK_METHOD1(Pay, bool(int));MOCK_METHOD0(Online, bool());
};
可以发现其方法的声明非常有规律。MOCK_METHOD后跟一个数字,该数字表明需要mock的函数有几个参数(除去this)。像第5行,Online()方法没有入参,则使用的是MOCK_METHOD0。而又两个参数的Login使用的是MOCK_METHOD2。MOCK_METHOD系列宏的第一个参数是函数名,第二个参数是函数指针的类型。
第二步,我们就可以设计测试场景了。在设计场景之前,我们先看一些Gmock的方法
// EXPECT_CALL(mock_object, Method(argument-matchers))
// .With(multi-argument-matchers)
// .Times(cardinality)
// .InSequence(sequences)
// .After(expectations)
// .WillOnce(action)
// .WillRepeatedly(action)
// .RetiresOnSaturation();
//
// where all clauses are optional, and .InSequence()/.After()/
// .WillOnce() can appear any number of times.
我们可以使用
- EXPECT_CALL声明一个调用期待,就是我们期待这个对象的这个方法按什么样的逻辑去执行。
- mock_object是我们mock的对象,上例中就是TestUser的一个对象。
- Method是mock对象中的mock方法,它的参数可以通过argument-matchers规则去匹配。
- With是多个参数的匹配方式指定。
- Times表示这个方法可以被执行多少次。如果超过这个次数,则按默认值返回了。
- InSequence用于指定函数执行的顺序。它是通过同一序列中声明期待的顺序确定的。
- After方法用于指定某个方法只能在另一个方法之后执行。
- WillOnce表示执行一次方法时,将执行其参数action的方法。一般我们使用Return方法,用于指定一次调用的输出。
- WillRepeatedly表示一直调用一个方法时,将执行其参数action的方法。需要注意下它和WillOnce的区别,WillOnce是一次,WillRepeatedly是一直。
- RetiresOnSaturation用于保证期待调用不会被相同的函数的期待所覆盖。
我们就可以基于以上的逻辑组织测试逻辑。
先举一个例子,我们要求Online在第一调用时返回true,之后都返回false。Login一直返回false。Pay一直返回true。也就是说用户第一次支付前处于在线状态,并可以支付成功。而第二次将因为不处于在线状态,要触发登录行为,而登录行为将失败。我们看下这个逻辑该怎么写
{TestUser test_user;EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(true));EXPECT_CALL(test_user, Login(_,_)).WillRepeatedly(testing::Return(false));EXPECT_CALL(test_user, Pay(_)).WillRepeatedly(testing::Return(true));Biz biz;biz.SetUser(&test_user);std::string admin_ret = biz.pay("user", "", 1);admin_ret = biz.pay("user", "", 1);}
第4行的意思是Online在调用一次后返回true,之后的调用返回默认的false。第5行意思是Login操作一直返回false,其中Login的参数是两个下划线(_),它是通配符,就是对任何输入参数都按之后要求执行。第6行意思是Pay操作总是返回true。那么我们在第10行和第11行分别得到如下输出
login status.pay success.
logout status.login error.
可以见得输出符合我们的预期。
我们再看一种场景,这个场景我们使用了函数参数的过滤。比如我们不允许admin的用户通过我们方法登录并支付,则可以这么写
{TestUser test_user;EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(false));EXPECT_CALL(test_user, Login("admin",_)).WillRepeatedly(testing::Return(false));Biz biz;biz.SetUser(&test_user);std::string admin_ret = biz.pay("admin", "", 1);}
第3行表示,如果Login的第一个参数是admin,则总是返回false。于是07行返回是
logout status.login error.
那么如果不是admin的用户登录,则返回成功,这个案例要怎么写呢?
{TestUser test_user;EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(false));EXPECT_CALL(test_user, Login(StrNe("admin"),_)).WillRepeatedly(testing::Return(true));EXPECT_CALL(test_user, Pay(_)).WillRepeatedly(testing::Return(true));Biz biz;biz.SetUser(&test_user);std::string user_ret = biz.pay("user", "", 1);}
03行使用了StrNe的比较函数,即Login的第一个参数不等于admin时,总是返回true。08行的输出是
logout status.login success.pay success.
我们再看一个例子,我们要求非admin用户登录成功后,只能成功支付2次,之后的支付都失败。这个案例可以这么写
{TestUser test_user;EXPECT_CALL(test_user, Online()).WillOnce(testing::Return(false));EXPECT_CALL(test_user, Login(StrNe("admin"),_)).WillRepeatedly(testing::Return(true));EXPECT_CALL(test_user, Pay(_)).Times(5).WillOnce(testing::Return(true)).WillOnce(testing::Return(true)).WillRepeatedly(testing::Return(false));Biz biz;biz.SetUser(&test_user);std::string user_ret = biz.pay("user", "", 1);user_ret = biz.pay("user", "", 1);user_ret = biz.pay("user", "", 1);}
第4行我们使用Times函数,它的参数5表示该函数期待被调用5次,从第6次的调用开始,返回默认值。Times函数后面跟着两个WillOnce,其行为都是返回true。这个可以解读为第一次和第二次调用Pay方法时,返回成功。最后的WillRepeatedly表示之后的对Pay的调用都返回false。我们看下执行的结果
logout status.login success.pay success.
logout status.login success.pay success.
logout status.login success.pay error.
从结果上看,前两次都支付成功了,而第三次失败。符合我们的期待。
下一节,我们将阅读Gmock的源码,分析其实现脉络和原理。
相关文章:
浪潮刘军:为什么说计算力是AI时代“免费的午餐”?
出品 | AI科技大本营(ID:rgznai100)产业AI、元脑生态是浪潮集团2019年度的两大关键词。作为一家以计算力为核心生产力的企业,浪潮还一直强调人工智能计算是未来最重要的计算力,而无论产业AI、元脑生态都构筑于计算的基础设施之上。…

Journey源码分析四:url路由
2019独角兽企业重金招聘Python工程师标准>>> 在入口函数main()的default分支中,对路由进行了注册,现在分析下。 ##main()中路由注册相关代码 源码: httpRouter : httptreemux.New() // Blog and pages as http server.InitializeBlog(httpRou…
“天河二号”总工程师杜云飞谈星光超算应用平台设计
整理 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】12 月 21-22 日,OpenI/O 启智开发者大会在深圳召开。在大会上, 国家超级计算广州中心总工程师、“天河二号”总工程师杜云飞发表了题为《星光超算应用平台》的主题报告&…

Google Mock(Gmock)简单使用和源码分析——源码分析
源码分析 通过《Google Mock(Gmock)简单使用和源码分析——简单使用》中的例子,我们发现被mock的相关方法在mock类中已经被重新实现了,否则它们也不会按照我们的期待的行为执行。我们通过阅读源码,来分析整个过程的实现逻辑。(转载…

远程控制软件VNC教程和对内网机器控制的实现
网络遥控技术是指由一部计算机(主控端)去控制另一部计算机(被控端),而且当主控端在控制端时,就如同用户亲自坐在被控端前操作一样,可以执行被控端的应用程序,及使用被控端的系统资源…

GRUB2相关概念
GNU GRUB,简称“GRUB”,是一个来自GNU项目的启动引导程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,…
朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型
做Linux网络开发,一般绕不开标题中几种网络编程模型。网上已有很多写的不错的分析文章,它们的基本论点是差不多的。但是我觉得他们讲的还不够详细,在一些关键论点上缺乏数据支持。所以我决定好好研究这几个模型。(转载请指明出于b…
支付宝账单出来后,除了总消费,你看到你的学习支出了吗?
当支付宝的2019年年度账单出来的时候很多人的第一反应就是我怎么花了这么多钱不少人都有这样的困惑忙忙碌碌一年到头,到底得到了什么?而这一切又和自己最开始的规划一样吗?其实从账单上可以看出你在2019年花费了哪些大头居家生活、穿衣打扮还…

体验Windows 7的Superbar
随着PDC 2008上Windows 7 M3 6801的发布,这个微软的下一代操作系统也渐渐浮出了水面。对于我们这些普通的PC用户而言,Windows 7相对于Windows Vista最显而易见的改变,无疑就是著名的Superbar任务栏了。说起它相比于原来的任务栏变化ÿ…

Linux 安装图形界面及远程连接
#可查询哪些组件是否已经安装(可用来对照组件名称) yum grouplistyum groupinstall X Window System -y #安装GNOME桌面环境 yum groupinstall GNOME Desktop Environment -y #安装KDE桌面环境 yum groupinstall KDE (K Desktop Environment)卸载 卸载GNOME桌面环境…
朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型
在《朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型》中我们分析了朴素模型的一个缺陷——一次只能处理一个连接。本文介绍的Select模型则可以解决这个问题。(转载请指明出于breaksoftware的csdn博客) 和朴素模型一样,我们首先…
微软开源NAS算法Petridish,提高神经网络迁移能力
作者 | Jesus Rodriguez译者 | Rachel编辑 | 夕颜出品 | AI科技大本营(ID:rgznai100) 【导读】神经架构搜索(Neural architecture search, NAS)是深度学习中最热门的趋势之一。NAS方法针对特定问题和数据…

[转]g++ 编译多个相关文件
三个文件,一个头文件,两个程序文件 /*d.h */#include <iostream>usingnamespacestd; classDataset { public: intgetdata(); }; /*d.cpp */#include "d.h"intDataset::getdata() { return1231; } /*out.cpp */#include <ios…

POJ--2391--Ombrophobic Bovines【分割点+Floyd+Dinic优化+二分法答案】最大网络流量
联系:http://poj.org/problem?id2391 题意:有f个草场,每一个草场当前有一定数目的牛在吃草,下雨时它能够让一定数量的牛在这里避雨,f个草场间有m条路连接,每头牛通过一条路从一点到还有一点有一定的时间花…
25年了,我总结出这些信息提取的经验教训
作者 | Ehud Reiter译者 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】近日,本文作者阿伯丁大学计算科学系教授 Ehud Reiter 及其带领的阅读小组读了一篇让他们印象深刻的论文——由 Ralph Grishman 发表的《信息提取 25 年》(…
朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型
在《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》中,我们分析了它只能支持1024个连接同时处理的原因。但是在有些需要同时处理更多连接的情况下,1024个连接往往是不够的,也就是不能够高并发。那么这个时候我们就可以采用…

flashcom中远程共享对象SharedObject的用法
觉得这篇文章比较好,转载回来。学习fcs也有差不多一个月了,感觉最有特色的东西还是SharedObject.SharedObject有不少东西,本地操作就不说了(相信很多人没接触fcs也用过);就说说远程共享对象吧.基本的应用流程是:my_nc new NetConnection(); my_nc.connect("rt…

Hive-1.2.0学习笔记(一)安装配置
鲁春利的工作笔记,好记性不如烂笔头下载hive:http://hive.apache.org/index.htmlHive是基于Hadoop的一个数据仓库工具,提供了SQL查询功能,能够将SQL语句解析成MapReduce任务对存储在HDFS上的数据进行处理。MySQ安装Hive有三种运行…

邮件安全隐患及其防范技术研究
邮件安全隐患及其防范技术研究<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />陈小兵【antian365.com】摘要电子邮件是Internet上使用最为频繁和广泛的服务,在给人们带来便利的同时,亦带来令人担忧的邮件…
必看!52篇深度强化学习收录论文汇总 | AAAI 2020
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送来源 | 深度强化学习实验室(ID:Deep-RL)作者 | DeepRLAAAI 2020 共收到的有效论文投稿超过 8800 篇,其中 7737 篇论文进入评审环节,最终收录数量…
朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型
在阅读完《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》和《朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型》两篇文章后,我们发现一个问题,不管select函数还是poll函数都不够智能,它们只能告诉我们成功…

Scala 深入浅出实战经典 第88讲:Scala中使用For表达式实现map、flatMap、filter
高级函数 map,flatMap,filter用for循环的实现。package com.dt.scala.forexpressionobject For_Advanced {def main(args: Array[String]) {}def map[A, B](list: List[A], f: A > B): List[B] for(element <- list) yield f(element)def flatMap[A, B](list: List[A], f…
抛弃Python,我们为什么用Go编写机器学习架构?
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送作者 | Caleb Kaiser译者 | 弯月,编辑 | 郭芮来源 | CSDN(ID:CSDNnews)如今,众所周知Python是机器学习项目中最流行的语言。尽管R、C…
朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较
经过之前四篇博文的介绍,可以大致清楚各种模型的编程步骤。现在我们来回顾下各种模型(转载请指明出于breaksoftware的csdn博客) 模型编程步骤对比《朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型》中介绍的是最基本的网络编程…

使用VM虚拟机的一点小技巧
今天想为朋友弄一个虚拟机系统文件,这样就可以直接拷贝过去,直接让他用了。哪成想电脑里的系统镜像文件不能用,也不知道是不是VM不支持,反正怎么着也引导不起来了。无奈只好用硬件光驱来装虚拟系统,把2003系统盘装入光…
翻译:AKKA笔记 - Actor消息 -1(二)
消息 我们只是让QuoteRequest到ActorRef去但是我们根本没见过消息类! 它是这样的:(一个最佳实践是把你的消息类包装在一个完整的对象里以利于更好的组织) TeacherProtocol package me.rerun.akkanotes.messaging.protocolsobject …

远程安装oracle 10.2.1 for redhat 5.0 2.6.18-53.el5xen
远程安装oracle <?xml:namespace prefix st1 ns "urn:schemas-microsoft-com:office:smarttags" />10.2.1 for redhat 5.0 2.6.18-53.el5xen<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />今天有个朋友打电…
伯克利新无监督强化学习方法:减少混沌所产生的突现行为
作者 | Glen Berseth译者 | Arvin编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100)【导读】所有生命有机体都在环境中占据一席之地,使它们在周围不断增加的熵中可以保持相对可预测性。例如,人类竭尽全力保护自己免受意外袭击--我们…
朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
在《朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较》一文中,我们分析了各种模型在处理短连接时的能力。本文我们将讨论处理长连接时各个模型的性能。(转载请指明出于breaksoftware的csdn博客) 我们可以想象下场景,…

Topcoder SRM 663 DIV 1
ABBADiv1 题意: 规定两种操作,一种是在字符串的末尾添加A,另一种是在末尾添加B然后反转字符串。现在给你一个起始串,一个终点串,然后问你是否能够通过以上两种操作,从起始串变为终点串。 题解: …