在进行测试过程中,待测的类或者方法经常会依赖其他类或方法的实现。如果此时这些依赖还没有实现,则需要打桩。另外测试讲求独立,测试之间的互相依赖会导致测试最终混乱不堪。

GoogleMock提供一套方法来快速的实现打桩,并让打桩的类或者方法轻松的按照你的要求来进行一系列动作。

现在有一个还没实现具体方法的的抽象基类

//MyClass.hpp
#pragma once class MyClass
{
public:virtual int add(int a, int b) = ; virtual int plus(int a, int b) = ;
};

一个要使用其方法的类

//UseMyClass.hpp
#pragma once #include "MyClass.hpp" class UseMyClass
{
public:
int useAddAndPlus(int a, int b)
{
return myclass->add(a, b) + myclass->plus(a, b);
} void set(MyClass* m)
{
myclass = m;
}
private:
MyClass* myclass;
};

现在要对UseMyClass进行单元测试,但它的方法又依赖于MyClass中方法的实现,这种情况下就要对MyClass进行mock

//MockMyClass.hpp
#pragma once #include <gmock/gmock.h>
#include "MyClass.hpp" class MockMyClass : public MyClass
{
public:
MOCK_METHOD2(add, int(int a, int b));
MOCK_METHOD2(plus, int(int a, int b));
};

最后在测试的时候调用mock的方法,并设置其预期的动作

//MockTest.cpp
#include <gtest/gtest.h>
#include "UseMyClass.hpp"
#include "MockMyClass.hpp" TEST(TestUseMyClass, useAddAndPlus)
{
UseMyClass useMyClass;
MockMyClass mockMyClass;
EXPECT_CALL(mockMyClass, add(,)).WillOnce(testing::Return());
EXPECT_CALL(mockMyClass, plus(,)).WillOnce(testing::Return());
useMyClass.set(&mockMyClass);
EXPECT_EQ(, useMyClass.useAddAndPlus(, ));
}

编译

g++ mockTest.cpp -lgtest -lgtest_main -lgmock  -lpthread -o myMock

运行结果

以上就是一个简单的使用GoogleMock的例子。下面介绍一下如何写mock的代码:

1. 必须包含头文件<gmock/hmock.h>

2. 对于一个待mock的方法

ReturnType func(arg0, arg1,....)

其mock方法的书写方式为:

MOCK_METHODn(func, ReturnType(arg0, arg1, ...))

其中n为参数个数

3. 对于在测试中mock方法的期待动作的基础写法:

EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);

EXPECT_CALL声明一个调用期待,就是我们期待这个对象的这个方法按什么样的逻辑去执行。

mock_object是mock的对象,例如上例中的mockMyClass

method是mock的方法,例如上例中的add, plus

Times表示这个方法期望被执行多少次

WillOnce表示执行一次方法时,将执行其参数action的方法。一般我们使用Return方法,用于指定一次调用的输出

WillRepeatedly表示一直调用方法时,将执行其参数action的方法。需要注意下它和WillOnce的区别,WillOnce是一次,WillRepeatedly是一直

举个例子:

EXPECT_CALL(mockMyClass, add(_,_))
.Times()
.WillOnce(Return())
.WillRepeatedly(Return())

这个例子表示,我们期望MyClass类的一个实例的方法add被调用6次,被调用是传入的参数不指定,但第一次被调用返回6,后面每次被调用返回3

例外注意,Times(cardinality) WillOnce(action) WillRepeatedly(action) 都不是必须要写的,按你自己的需要去选择要写哪个或者哪些

在公司的测试代码中像上例这种情况很少见,公司代码中mock不是为了为那些没有实现的方法打桩,而是为了减少UT之间的相互依赖。

试想如果class A 依赖于class B的实现,如果不给B打桩的话,A的UT肯定会依赖于B的实现,而有了mock则可以直接对依赖B的方法直接打桩而不去管B的真正实现,减少了测试的耦合性,使得测试间互相独立,容易调试。

下面对这种减少依赖而使用mock的情况举个例子:

一个实现其自己的方法的MyClass

//MyClass.hpp
#pragma once #ifdef UT
#include "MockMyClass.hpp"
class MyClass_orig
#else
class MyClass
#endif
{
public:
int add(int a, int b)
{
return a + b;
} int plus(int a, int b)
{
return a * b;
}
};

一个类的方法依赖于其他类(MyClass)方法的类UseMyClass

//UseMyClass.hpp
#pragma once #include "MyClass.hpp" class UseMyClass
{
public:
int useAddAndPlus(int a, int b)
{
return myclass->add(a, b) + myclass->plus(a, b);
} void set(MyClass* m)
{
myclass = m;
}
private:
MyClass* myclass;
};

对MyClass进行mock

//MockMyClass.hpp
#pragma once #include <gmock/gmock.h> class MyClass
{
public:
MOCK_METHOD2(add, int(int a, int b));
MOCK_METHOD2(plus, int(int a, int b));
};

最后对UseMyClass 进行测试

#define UT

#include <gtest/gtest.h>
#include "UseMyClass.hpp" TEST(TestUseMyClass, useAddAndPlus)
{
UseMyClass useMyClass;
MyClass mockMyClass;
EXPECT_CALL(mockMyClass, add(,)).WillOnce(testing::Return());
EXPECT_CALL(mockMyClass, plus(,)).WillOnce(testing::Return(2));
useMyClass.set(&mockMyClass);
EXPECT_EQ(, useMyClass.useAddAndPlus(, ));
}

编译

g++ mockTest.cpp -lgtest -lgtest_main -lgmock  -lpthread -o myMock

运行结果

注意,我故意让plus返回2,这样可以看出最后测试的时候用的是mock的类方法而非真正的类方法。

参考文章:

https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md

GoogleMock初探(0)的更多相关文章

  1. Arcade初探[0] 目录与导航

    2017年6月,ESRI开发者页面出现了一个新玩意儿:Arcade. 连接:点我 这是什么东西呢?有什么用呢? 1. 是什么 Arcade一种表达语言,可以在ArcGIS平台上使用.不管是编写简单的脚 ...

  2. GoogleTest初探(0)

    单元测试是一种保证代码质量的手段.程序员可以通过写单元测试来保证自己写的代码的功能正确. 本人所在公司使用GoogleTest测试框架来进行单元测试.虽然现在在公司的工程代码中写单元测试已经驾轻就熟, ...

  3. Spring入门(9)-AOP初探

    Spring入门(9)-AOP初探 0. 目录 什么是面向切面编程 AOP常见术语 AOP实例 参考资料 1. 什么是面向切面编程 Aspect Oriented Programming(AOP),即 ...

  4. ZAM 3D 制作简单的3D字幕 流程(二)

    原地址:http://www.cnblogs.com/yk250/p/5663907.html 文中表述仅为本人理解,若有偏差和错误请指正! 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇 ...

  5. ZAM 3D 制作3D动画字幕 用于Xaml导出

    原地址-> http://www.cnblogs.com/yk250/p/5662788.html 介绍:对经常使用Blend做动画的人来说,ZAM 3D 也很好上手,专业制作3D素材的XAML ...

  6. 微信小程序省市区选择器对接数据库

    前言,小程序本身是带有地区选着器的(网站:https://mp.weixin.qq.com/debug/wxadoc/dev/component/picker.html),由于自己开发的程序的数据是很 ...

  7. osg编译日志

    1>------ 已启动全部重新生成: 项目: ZERO_CHECK, 配置: Debug x64 ------1> Checking Build System1> CMake do ...

  8. Android BLE与终端通信(五)——Google API BLE4.0低功耗蓝牙文档解读之案例初探

    Android BLE与终端通信(五)--Google API BLE4.0低功耗蓝牙文档解读之案例初探 算下来很久没有写BLE的博文了,上家的技术都快忘记了,所以赶紧读了一遍Google的API顺便 ...

  9. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

    更新 1.如果看不懂本文,或者比较困难,先别着急问问题,我单写了一个关于依赖注入的小Demo,可以下载看看,多思考思考注入的原理: https://github.com/anjoy8/BlogArti ...

随机推荐

  1. intelliJ IDEA 怎么添加本地的idea web项目

    概述:这篇文章主要讲述idea开发工具怎么添加本地的idea web项目. 一:首先介绍一下idea web项目的目录结构: 上图详细简单的说了一下idea web项目的文件情况. 二:说明一下部署本 ...

  2. 个人项目-wordcount

    源代码上传到github的网址为:https://github.com/fancy-dawning/hello-world.git. wc.exe是一个常见的工具,它能统计文本文件的字符数,单词数和行 ...

  3. 网络I/O虚拟化,SR-IOV技术

    1.简介 网络I/O虚拟化是服务器虚拟化技术的重要组成部分,在服务器虚拟化技术领域,计算虚拟化(如CPU和内存虚拟化)已经日趋成熟,但是,网络I/O虚拟化技术的发展相对比较滞后.当前,主流的网络I/O ...

  4. 毕向东_Java基础视频教程第20天_IO流(5~6)

    第20天-05-IO流(文件列表一) static File[] listRoots() List the available filesystem roots. String[] list() Re ...

  5. Ionic微信开发之环境配置

    在开发微信版的H5页面时,如果需要正常调用微信公众号的开放接口(测试或者发布情况),根据官方要求需要保证网页域名和后端维护的一致.因此,进行真服测试就显得很有必要.WebStorm提供了实时远程部署的 ...

  6. 小J学python--Exception-异常

    现在我们要打开一个名为fuck的文件,fuck是不存在的,看看异常是怎么工作的 不捕获异常的情况 #打开文件 open('fuck') 执行结果 捕获所有异常 Exception是所有异常类的父类,所 ...

  7. python选课系统

    程序名称: 选课系统 角色:学校.学员.课程.讲师 要求: 1. 创建北京.上海 2 所学校 2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海 ...

  8. 4、集合set的功能介绍

    集合是易变(可改变)和无序聚集.集合set支持迭代,很像无值(或仅有键的)字典,用花括号表示{}.   1.集合的创建: 可以通过调用内建函数set()来创建,及向其传递一个迭代,该迭代的项目成为形成 ...

  9. 3669. [NOI2014]魔法森林【LCT 或 SPFA动态加边】

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

  10. 随手练——S(n)=O(1),判断一个链表是否为“回文”

    方法一:T(n)=O(n),S(n)=O(n) 走完一遍链表,每个值入栈,之后再走一遍链表,和每次弹出的栈顶进行比较. 核心: LNode *p = l->next; while (p) { s ...