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

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. AngularJS+RequireJs实现动态加载JS和页面的方案研究【下】

    about.js: [html] view plain copy 在CODE上查看代码片派生到我的代码片 define(['app'], function(app) { app.controller( ...

  2. 毕向东_Java基础视频教程第21天_IO流(1)

    第21天-01-IO流(对象的序列化) ObjectInputStream与ObjectOutputStream 被操作的对象需要实现Serializable接口(标记接口) 非必须, 但强烈建议所有 ...

  3. 如何提高Ajax性能

    1.适当使用缓存机制 2.使用CDN内容分发来访问Jquery脚本: (1)自己公司架设CDN服务器 (2)使用第三方公司的,比如微软,谷歌等公司的CDN,但有时候不太靠谱 3.JS/CSS文件的打包 ...

  4. POP动画[3]

    POP动画[3] 这一节主要讲解POP动画的自定义动画属性. POP动画中有一个参数,叫timingFunction,与CoreAnimation中的一个参数CAMediaTimingFunction ...

  5. webpack笔记三 管理输出

    webpack笔记三 管理输出 增加src/print.js: export default function printMe() { console.log('I get called from p ...

  6. Python学习---深入编码学习1225

    1.1. Python2 Py2中只有2中数据类型,Str和Unicode,而且str中保存的是bytes,Unicode中保存的是unicode 一切我们能看到的明文都是unicode数据类型, b ...

  7. Asp.Net MVC源码调试

    首先下载MVC源代码,下载地址为:https://aspnetwebstack.codeplex.com/ 打开项目,卸载test文件夹下的所有项目和System.Web.WebPages.Admin ...

  8. ZT fcntl设置FD_CLOEXEC标志作用

    fcntl设置FD_CLOEXEC标志作用 分类: C/C++ linux 2011-11-02 22:11 3217人阅读 评论(0) 收藏 举报 bufferexegccnullfile 通过fc ...

  9. 021.10 IO流 打印流

    内容:PrintStream:字节流    PrintWriter:字符流 PrintStream public static void main(String[] args) throws IOEx ...

  10. 在ubuntu上使用QQ的经历

    pidgin-lwqq: 项目首页:https://github.com/xiehuc/pidgin-lwqq sudo add-apt-repository ppa:lainme/pidgin-lw ...