Google Mock启蒙篇matcher详细尽说明

2023-11-13

Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译)

来自:Koala++'s blog   |  时间:2012-08-06 19:24:04  

原文链接: http://quweiprotoss.blog.163.com/blog/static/4088288320111022103458507/

Setting Expectations

    成功地使用 Mock 对象的关键是在它上面设置合适的期望。如果你设置的期望太过严格,你的测试可能会因为无关的改变而失败。如果你把期望设置的太过松驰, bugs可能会溜过去。而你需要的是你的测试可以刚好捕获你想要捕获的那一种 bug Google Mock 提供了一些方法可以让你的测试尺度 刚好 ( just right ) 

General Syntax

     Goolge Mock 中,我们用 EXPECT_CALL() 宏来设置一个 Mock 函数上的期望。一般语法是:

EXPECT_CALL(mock_object, method(matchers)) <xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

    .Times(cardinality)

    .WillOnce(action)

.WillRepeatedly(action);

这个宏有两个参数:第一个是 Mock 对象,第二个参数是函数和它的参数。注意两个参数是用逗号 ( , ) 分隔的,而不是句号 ( . ) 

这个宏可以跟一些可选 子句 ,这些子句可以提供关于期望更多的信息。我们将会在下面的小节中介绍每个子句有什么意义。

这些语法设计的一个目的是让它们读起来像是英语。比如你可能会直接猜出下面的代码是有什么含义

using ::testing::Return;...

EXPECT_CALL(turtle, GetX())

    .Times(5)

    .WillOnce(Return(100))

    .WillOnce(Return(150))

.WillRepeatedly(Return(200));

公布答案, turtle 对象的 GetX() 方法会被调用 5 次,它第一次返回 100 ,第二次返回 150 ,然后每次返回 200 。许多人喜欢称这种语法方式为特定领域语言 ( Domain-Specific Language (DSL) ) 

注意: 为什么我们要用宏来实现呢?有两个原因:第一,它让期望更容易被认出来 (无论是 grep 还是人去阅读 ) ,第二,它允许 Google Mock 可以得到失败期望在源文件的位置,从而使 Debug 更容易。

Matchers: What Arguments Do We Expect?

    当一个 Mock 函数需要带参数时,我们必须指定我们期望的参数的是什么;比如:

// Expects the turtle to move forward by 100 units.

EXPECT_CALL(turtle, Forward(100));

    有时你可能不想指定的太精确 ( 还记得前面测试不应太严格吗?指定的太精确会导致测试健壮性不足,并影响测试的本意。所以我们鼓励你只指定那些必须要指定的参数,不要多,也不要少 ) 。如果你只关心 Forward 是否会被调用,而不关心它用什么参数,你可以写 _ 作为参数,它的意义是“任意”参数。

using ::testing::_;

...

// Expects the turtle to move forward.

EXPECT_CALL(turtle, Forward(_));

    _ 是我们称为 Matchers 的一个例子,一个 matcher 是像一个断言,它可测试一个参数是否是我们期望的。你可用在 EXPECT_CALL() 中任何写函数参数期望的地方用matcher 

    一个内置的 matchers 可以在 CheatSheet 中找到,比如,下面是 Ge( greater than or equal ) matcher 的应用。

using ::testing::Ge;...

EXPECT_CALL(turtle, Forward(Ge(100)));

    这个测试是检查 turtle 是否被告知要至少前进至少 100 个单位。

Cardinalities: How Many Times Will It Be Called?

     EXPECT_CALL() 之后第一个我们可以指定的子句是 Times() 。我们称 Times的参数为 cardinality ,因为它是指这个函数应该被调用 多少次 。 Times 可以让我们指定一个期望多次,而不用去写一次次地写这个期望。更重要的是, cardinality可以是“模糊”的,就像 matcher 一样。它可以让测试者更准确地表达他测试的目的。

    一个有趣的特例是我们指定 Times(0) 。你也许已经猜到了,它是指函数在指定参数下不应该被调用,如果这个函数被调用了, Google Mock 会报告一个 Google Test 失败。

    我们已经见过 AtLeast(n) 这个模糊 cardinalities 的例子了。你可以在CheatSheet 中找一个内置 cardinalities 列表。

    Times() 子句可以省略。 如果你省略 Times()  Google Mock 会推断出cardinality 的值是什么。 这个规则很容易记:

  如果在 EXPECT_CALL 中 既没有 WillOnce() 也没有 WillRepeatedly() ,那推断出的 cardinality 就是 Times(1) 

  如果有 n  WillOnce() ,但 没有 WillRepeatedl() ,其中 n >= 1 ,那么cardinality 就是 Times(n) 

  如果有 n  WillOnce() ,和一个 WillRepeatedly() ,其中 n >= 0 ,那么cardinality 就是 Times(AtLeast(n)) 

小测试: 如果一个函数期望被调用 2 次,但被调用了 4 次,你认为会发生什么呢?

Actions: What Should It Do?

    请记住一个 Mock 对象其实是没有实现的。是我们这些用户去告诉它当一个函数被调用时它应该做什么。这在 Google Mock 中是很简单的。

    首先,如果 Mock 函数的返回类型是一个指针或是内置类型,那这个函数是有 默认行为 的 ( 一个 void 函数直接返回, bool 函数返回 false ,其它函数返回 0 ) 。如果你不想改变它,那这种行为就会被应用。

    其次,如果一个 Mock 函数没有默认行为,或默认行为不适合你,你可以用WillOnce 来指定每一次的返回值是什么,最后可以选用 WillRepeatedly 来结束。比如:

using ::testing::Return;...

EXPECT_CALL(turtle, GetX())

    .WillOnce(Return(100))

    .WillOnce(Return(200))

  .WillOnce(Return(300));

上面的意思是 turtle.GetX() 会被调用 恰好 3 次,并分别返回 100  200  300 

using ::testing::Return;...

EXPECT_CALL(turtle, GetY())

.WillOnce(Return(100))

   .WillOnce(Return(200))

.WillRepeatedly(Return(300));

上面的意思是指 turtle.GetY() 将 至少 被调用 2 次,第一次返回 100 ,第二次返回200 ,从第三次以后都返回 300 

当然,你如果你明确写上 Times()  Google Mock 不会去推断 cardinality 了。如果你指定的 cardinality 大于 WillOnce() 子句的个数时会发生什么呢?嗯,当WillOnce() 用完了之后, Google Mock 会每次对函数采用 默认 行为。

    我们在 WillOnce() 里除了写 Return() 我们还能做些什么呢?你可以用ReturnRef( variable ) ,或是调用一个预先定义好的函数,自己在 Others 中找吧。

重要提示: EXPECT_CALL() 只对行为子句求一次值,尽管这个行为可能出现很多次。所以你必须小心这种副作用。下面的代码的结果可能与你想的不太一样。

int n = 100;

EXPECT_CALL(turtle, GetX())

.Times(4)

.WillRepeatedly(Return(n++));

    它并不是依次返回 100  101  102... ,而是每次都返回 100 ,因为 n++ 只会被求一次值。类似的, Return(new Foo)  EXPECT_CALL() 求值时只会创建一个Foo 对象,所以它会每次都返回相同的指针。如果你希望每次都看到不同的结果,你需要定义一个自定义行为,我们将在 CookBook 中指导你。

    现在又是一个小测验的时候了!你认为下面的代码是什么意思?

using ::testing::Return;...

EXPECT_CALL(turtle, GetY())

.Times(4)

.WillOnce(Return(100));

    显然, turtle.Get() 期望被调用 4 次。但如果你认为它每次都会返回 100 ,那你就要再考虑一下了!记住,每次调用都会消耗一个 WillOnce() 子句,消耗完之后,就会使用默认行为。所以正确的答案是 turtle.GetY() 第一次返回 100 ,以后每次都返回 0 ,因为 0 是默认行为的返回值。

Using Multiple Expectations

    至今为止,我们只展示了如何使用单个期望。但是在现实中,你可能想指定来自不同 Mock 对象的 Mock 函数上的期望。

    默认情况下,当一个 Mock 函数被调用时, Google Mock 会通过定义顺序的 逆序去查找期望,当找到一个与参数匹配的有效的期望时就停下来 ( 你可以把这个它想成是“老的规则覆盖新的规则“ ) 。如果匹配的期望不能再接受更多的调用时,你就会收到一个超出上界的失败,下面是一个例子:

using ::testing::_;...

EXPECT_CALL(turtle, Forward(_));   // #1

EXPECT_CALL(turtle, Forward(10))   // #2

    .Times(2);

如果 Forward(10) 被连续调用 3 次,第 3 次调用它会报出一个错误,因为最后一个匹配期望 (#2) 已经饱和了。但是如果第 3 次的 Forward(10) 替换为 Forward(20) ,那它就不会报错,因数现在 #1 将会是匹配的期望了。

边注: 为什么 Google Mock 会以 逆序 去匹配期望呢?原因是为了可以让用户开始时使用 Mock 对象的默认行为,或是一些比较松驰的匹配条件,然后写一些更明确的期望。所以,如果你在同一个函数上有两个期望,你当然是想先匹配更明确的期望, 然后 再匹配其它的,或是可以说明确的规则会隐藏更宽泛的规则。

Ordered vs Unordered Calls

    默认情况下,即使是在前一个期望没有被匹配的情况下,一个期望仍然可以被匹配。换句话说,调用的匹配顺序不会按照期望指定的顺序去匹配。

    有时,你可能想让所有的期望调用都以一个严格的顺序来匹配,这在 Google Mock 中是很容易的:

using ::testing::InSequence;...

TEST(FooTest, DrawsLineSegment) {

  ...

  {

    InSequence dummy;

 

    EXPECT_CALL(turtle, PenDown());

    EXPECT_CALL(turtle, Forward(100));

    EXPECT_CALL(turtle, PenUp());

  }

  Foo();

}

    创建 InSequence 的一个对象后,在这个对象作用域中的期望都会以 顺序 存放,并要求调用以这个 顺序 匹配。因为我们只是依赖这个对象的构造函数和析构函数来完成任务,所以对象的名字并不重要。

( 如果你只是关心某些调用的相对顺序,而不是所有调用的顺序?可以指定一个任意的相对顺序吗?答案是 ... 可以!如果你比较心急,你可以在 CookBook 中找到相关的细节。 )

All Expectations Are Sticky (Unless Said Otherwise)

    现在让我们做一个小测验,看你掌握 Mock 到什么程度了。你如何测试 turtle 恰好 经过原点两次?

    当你想出你的解法之后,看一下我们的答案比较一下 ( 先自己想,别作弊 ) 

using ::testing::_;...

EXPECT_CALL(turtle, GoTo(_, _))   // #1

    .Times(AnyNumber());

EXPECT_CALL(turtle, GoTo(0, 0))   // #2

.Times(2);

假设 turtle.GoTo(0,0) 被调用了 3 次。在第 3 次, Google Mock 会找到参数匹配期望 #2 。因为我们想要的是恰好经过原点两次,所以 Google Mock 会立即报告一个错误。上面的内容其实就是我们在“ Using Multiple Expectations ”中说过的。

    上面的例子说明了 Google Mock 中 默认情况下期望是严格的 ,即是指期望在达到它们指定的调用次数上界后仍然是有效的。这是一个很重要的规则,因为它影响着指定的意义,而且这种规则与许多别的 Mock 框架中是 不一样 的 ( 我们为什么会设计的不一样?因为我们认为我们的规则会使一般的用例更容易表达和理解 ) 

    简单?让我看一下你是不是真懂了:下面的代码是什么意思:

using ::testing::Return;

...

for ( int i = n; i > 0; i--) {

  EXPECT_CALL(turtle, GetX())

      .WillOnce(Return(10*i));

}

    如果你认为 turtle.GetX() 会被调用 n 次,并依次返回 10, 20, 30, ... ,唉,你还是再想想吧!问题是,我们都说过了,期望是严格的。所以第 2 turtle.GetX() 被调用时,最后一个 EXPECT_CALL() 会被匹配,所以马上会引起“超出上界”的错误。上面的代码其实没什么用途。

    一个正确表达 turtle.GetX() 返回 10, 20, 30,..., 的方法是明确地说明期望不是 严格的。换句话说,在期望饱和之后就 失效 。

using ::testing::Return;

...

for ( int i = n; i > 0; i--) {

  EXPECT_CALL(turtle, GetX())

    .WillOnce(Return(10*i))

    .RetiresOnSaturation();

}

    并且,有一个更好的解决方法,在这个例子中,我们期望调用以特定顺序执行。因为顺序是一个重要的因素,我们应该用 InSequence 明确地表达出顺序:

using ::testing::InSequence;

using ::testing::Return;

...

{

  InSequence s;

 

  for ( int i = 1; i <= n; i++) {

    EXPECT_CALL(turtle, GetX())

        .WillOnce(Return(10*i))

        .RetiresOnSaturation();

  }

}

    顺便说一下,另一个期望可能 不 严格的情况是当它在一个顺序中,当这个期望饱和后,它就自动失效,从而让下一个期望有效。

Uninteresting Calls

    一个 Mock 对象可能有很多函数,但并不是所有的函数你都关心。比如,在一些测试中,你可能不关心 GetX()  GetY() 被调用多少次。

     Google Mock 中,你如果不关心一个函数,很简单,你什么也不写就可以了。如果这个函数的调用发生了,你会看到测试输出一个警告,但它不会是一个失败。

What Now?

    恭喜!你已经学习了足够的 Google Mock 的知识了,你可以开始使用它了。现在你也许想加入 googlemock 讨论组,并开始真正地用 Google Mock 开始写一些测试——它是很有意思的,嗨,这可能是会上瘾的,我可是警告过你了喔!

    如果你想提高你的 Mock 等级,你可以移步至 CookBook 。你可以在那学习更多的Google Mock 高级特性——并提高你的幸福指数和测试快乐级别。

Copyright notice

    所有的内容全部翻译自  Google 的文档  Google C++ Mocking Framework for Dummies ,  Koala++/ 屈伟 如果在法律上拥有译作的版权,在此声明愿意自动放弃。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Google Mock启蒙篇matcher详细尽说明 的相关文章

  • GDB远程调试技术---基于mini2440

    GDB调试器提供了两种不同的调试代理用于支持远程调试 即gdbserver方式和stub 插桩 方式 这两种远程调试方式是有区别的 gdbserver本身的体积很小 能够在具有很少存储容量的目标系统上独立运行 因而非常适合于嵌入式环境 而s
  • 8.基于STM32C8T6的四旋翼无人机的飞控制作----实践操作3,AD电路板绘制-封装库绘制

    封装库的绘制 说实话 大部分的元器件的 封装都不用自己画 但是前提是你的小仓库中有你所用元器件的封装 如图和原理图库界面类似 左侧为库中各个元件的列表 能复制进来其他库的元件 也是双击修改名字等 右键新建元件 使用右上角的图标放置焊盘 字符
  • 华为OD机试真题-等和子数组的最小和【2023Q1】

    题目描述 给定一个数组nums 将元素分为若干个组 使得每组和相等 求出满足条件的所有分组中 组内元素和的最小值 输入描述 第一行输入 m 接着输入m个数 表示此数组 数据范围 1 lt M lt 50 1 lt nums i lt 50
  • python编程菱形_Python—什么是菱形继承

    继承是面向对象编程的一个重要的方式 通过继承 子类就可以扩展父类的功能 在python中一个类能继承自不止一个父类 这叫做python的多重继承 Multiple Inheritance 语法 class SubclassName Base
  • 布隆过滤器实战【防止缓存击穿】

    为什么引入 我们的业务中经常会遇到穿库的问题 通常可以通过缓存解决 如果数据维度比较多 结果数据集合比较大时 缓存的效果就不明显了 因此为了解决穿库的问题 我们引入Bloom Filter 适合的场景 数据库防止穿库 Google Bigt
  • Minecraft外置登录服务器Little-Skin讲解

    随着Minecraft的普及与发展 现在许多小伙伴是越来越爱上了MC 但是想玩国际正版岂是那么容易 或许你会说 HMCL不就是java启动器吗 这句话是没错 但是HMCL的都是离线账户 那么该怎么永远拥有一个稳定的账户呢 这就是今天为大家分
  • nginx try_files流程解析

    前端部署单页应用时在nginx上经常用到try files指令 而对于try files并不知道其所以然 所以花时间整理总结如下 Syntax try files file uri try files file code Default C
  • 好久没写东西了!!!

    最近存储升级 一直忙着这个 这个事情不弄完 心里总是不踏实 毕竟所有的数据都在上面呢 预计这个月中旬就可以完成了 也可以安稳下了看些东西了 最近烦 烦 烦
  • DWDM原理与光纤传输

    文章目录 波分复用WDM DWDM解决问题 特点 超长距离 无电 中继传输 降低成本 WDM 类别分类 波分系统的基本组成 波分技术的优势 DWDM网元基本类型 波分常见站点类型 OTM Optical Terminal Multiplex
  • 关于控制下拉框select只读的js控制

    关于控制下拉框select只读的js控制 文本框有readonly属性 直接设置 下拉框没有readonly属性 也不能通过其他属性进行只读的设置 下拉框只有disabled属性 但是这个属性设成true之后 值就获取不到了 我在网上搜了一
  • 常用矩阵求导公式

    常用矩阵求导公式 在学习张量分解 TUCKER or CP 分解的时候 我们经常会遇到各式各样的优化模型 其中最简单的就是对代价函数 cost function 进行求导然后通过梯度下降法 gradient decent method 共轭
  • 使用 DeferredResult 实现相应的异步生成返回值的功能

    最近使用了 DeferredResult 来实现相应的异步生成返回值的功能 来这里记录一下 官方文档中说DeferredResult和Callable都是为了异步生成返回值提供基本的支持 简单来说就是一个请求进来 如果你使用了Deferre
  • 扩展欧几里得算法详解

    为了介绍扩展欧几里得 我们先介绍一下贝祖定理 即如果a b是整数 那么一定存在整数x y使得ax by gcd a b 换句话说 如果ax by m有解 那么m一定是gcd a b 的若干倍 可以来判断一个这样的式子有没有解 有一个直接的应

随机推荐

  • c花体复制_可复制花体字大全?

    匿名用户 1级 2017 12 01 回答 花体需要柔软的有弹性的笔尖去表现粗细的变化 用较细的笔尖尖端去表现游丝的生动 因而对于花体英文书写来说重要的是笔尖而非笔杆 新手建议使用诸如Gillot 404 hunt101 56 22b hi
  • vue实现简单的登入功能

    html部分
  • vue自定义指令的创建和使用

    1 bind 只调用一次 指令第一次绑定到元素时调用 用这个钩子函数可以定义一个绑定时执行一次的初始化动作 2 inserted 被绑定元素插入父节点时调用 父节点存在即可调用 不必存在于document中 3 update 被绑定于元素所
  • 华为IC岗笔试刷题含答案(2)

    目录 单选 多选 判断 单选 1 的目的都是关注单元模块的集成 功能组合 模块间的接口及时序 sub chip本身的设计功能和规格正确性 A 集成验证 IT B FPGA原型验证 C 系统验证ST D 单元验证UT 2 关于多bit信号的异
  • react学习之完善官网游戏教程

    react学习之完善官网游戏教程 1 在游戏历史记录列表显示每一步棋的坐标 格式为 列号 行号 2 在历史记录列表中加粗显示当前选择的项目 3 使用两个循环来渲染出棋盘的格子 而不是在代码里写死 hardcode 4 添加一个可以升序或降序
  • 203实验室启动conda

    启动conda 环境 由于我们没有conda init 以后每次启动都需要用这个命令 source miniconda3 bin activate
  • CentOS 编译错误+配置错误解决方法集合

    ERROR the HTTP XSLT module requires the libxml2 libxslt yum y install libxml2 libxml2 dev yum y install libxslt devel 1
  • 基于OpenCV的简易实时手势识别(含代码)

    基于OpenCV的简易实时手势识别 1 基本信息介绍 1 1实验步骤 1 2效果展示 2 肤色检测 二值化 开运算 高斯模糊 2 1 flip 函数原型 2 2cvtColor 函数原型 2 3split 函数原型 2 4GaussianB
  • C++ stack容器-50-栈容器基本概念和常用接口

    接着学习下一个容器 stack 栈容器 当然后面还要学习一个队列容器 两个有点相似一般一起对比和学习 本篇主要学习栈容器的基本概念和常用接口的基本使用 1 什么是stack stack是一种先进后出 First In Last Out FI
  • 开发中遇到不好解决的问题记录

    1 本地和测试和真实模拟数据 本地连接生产环境且登录相关用户token 都重现不了 后面管理员账号转交成功了 重现不了用户报的错
  • 【MAC终端UI自动化】pyautogui.click,图像识别定位不准排查

    原始代码 点不到图片位置 x y pyautogui locateCenterOnScreen image 1 png pyautogui click x y 排查一 没有鼠标点击的权限 打开系统偏好设置 gt 安全与隐私 gt 在 允许下
  • 国家医保服务平台js逆向(SM4+SM2)

    网站 aHR0cHM6Ly9mdXd1Lm5oc2EuZ292LmNuL25hdGlvbmFsSGFsbFN0LyMvc2VhcmNoL21lZGljYWwtc2VydmljZT9jb2RlPTkwMDAwJmZsYWc9ZmFsc2UmZ
  • 梯度下降算法介绍

    最优化 Optimization 在我们的日常生活中扮演着重要角色 最优化意味着找到问题的最优解 在机器学习中 通过训练集数据找到最优解 并在验证集上进行检测 许多机器学习算法都需要用到最优化 例如线性回归 linear regressio
  • Flutter中MethodChannel/EventChannel的原理

    前言 Flutter开发中或多或少都需要和原生端做一些交互 Flutter SDK中也为开发者提供了MethodChannel EventChannel实现了Flutter调用原生端以及原生端调用Flutter MethodChannel
  • 爬虫第一篇——Anaconda与jupyter安装配置与使用

    Anaconda与jupyter安装配置与使用 1 anaconda安装 进入官网下载 1 进去之后选择与自己电脑版本相匹配的版本下载 比如我的电脑是win10 64位 点击之后下载 下载完成后打开所在文件夹 右键 管理员身份运行 点击fi
  • Ice Skating CodeForces - 217A(并查集基本操作)

    题意 给出n个点的坐标 如果两个点x相同或者y相同 则两点可以联通 问你最少加几条线 能使全部点联通 AC代码 include
  • web前端顶岗实习总结报告_web前端年度工作总结范文

    web前端年度工作总结范文 导语 WEB前端是现在it行业是一件伤脑力和高报酬的工作 下面小编整理了web前端年度工作总结范文 欢迎参考借鉴 web前端年度工作总结 从入职到现在 我在导师的指导下走上了前端之路 在这段时间的学习和项目中使我
  • angularJS的文件的下载

    一 使用window location href url的方式 这种方式可以获取到要下载的文件 但是当下载的文件不存在 或者下载过程中后台报错的话会发生跳转 二 使用 http实现异步无刷新的下载文件 1 http method post
  • FRP进阶篇之安全认证

    目录 一 前言 二 通信加密 1 概述 2 使用 三 BasicAuth 鉴权 1 概述 2 使用 2 1 客户端配置 2 2 启动客户端 2 3 效果验证 四 TLS双向身份验证 1 概述 2 使用 2 1 生成证书 2 2 服务端配置
  • Google Mock启蒙篇matcher详细尽说明

    Google Mock启蒙篇 2 Google C Mocking Framework for Dummies 翻译 来自 Koala s blog 时间 2012 08 06 19 24 04 原文链接 http quweiprotoss