一、gmock是什么

gmock是google公司推出的一款开源的白盒测试工具。gmock是个很强大的东西,测试一个模块的时候,可能涉及到和其他模块交互,可以将模块之间的接口mock起来,模拟交互过程。其作用就类似白盒测试中的打桩的概念。

下面简单的说说打桩在白盒测试中的重要性:

1、比如银行业务,需要测试业务模块。此时,不可能去操作真实的数据库,并且搭建新的数据库可能比较复杂或者耗时。那么就可以用gmock将数据库接口地方打桩,来模拟数据库操作。

2、比如要测试A模块,必过A模块需要调用B模块的函数。如果B模块还没有实现,此时,就可以用gmock将B模块的某些接口打桩。这样就可以让A模块的测试继续进行下去。

3、比如网关设备,在用gtest测试device模块的时候,必须有真实的设备才能让测试进行下去。如果用gmock模拟一套sdk接口,那么无需真实的设备也能让测试进行下去。(本条仅限公司内部阅读)

二、gmock如何获取

gmock是google的开源工具,google的官网上是可以下载源码的。不过公司内部员工可以去0.2上去取,在“研发质量部”的文件夹下。gmock的最新版本是1.7.0。下载下来的压缩包名称为“gmock-1.7.0.zip”。解压后,如下:

仔细观察发现,压缩包里面有gtest的文件夹,该文件夹里面就是gtest的源码。因为大部分情况下,gmock是配合gtest来做白盒测试的。关于gtest的工程相关介绍请查看本博客其他文章。

本文暂时讨论windows下的gmock编译,工程相关的文件在msvc的文件夹中。msvc文件夹下又分为2005和2010文件夹,分别是用VS2005和VS2010建立的工程。

用VS2010打开工程,然后直接编译。编译通过后,会得到gmock.lib,gmock_maim.lib,gmock_test.ext三个文件。其中gmock.lib就是我们所需要的库文件,其他两个工程本文暂不做阐述。

三、gmock的第一个demo

我们暂且模拟银行转账系统。银行转账系统涉及到数据库两个操作,首先要通过银行卡ID找到账户信息(包括账户余额等),然后在通过计算,将转账后的金额写入到转账双方。这样就完成了简单的银行转账业务。

下面我们来mock(模拟)数据库的查询账户和写入金额的两个方法,定义一个头文件AccountManager.h :

// AccountManager.h
// the interface of external services which should be mocked
// 需要被mock的服务接口
#pragma once #include <string> #include "Account.h" class AccountManager
{
public:
//通过账户号,找到对应的用户
virtual Account findAccountForUser(const std::string& userId) = ;
//更新用户的信息这里
virtual void updateAccount(const Account& account) = ;
};

AccountManager是需要被mock(模拟)的类。其中findAccountForUser(找到对应用户)和updateAccount(更新账户信息)是本次转账要mock的两个方法。注意,此处的两个方法用的是纯虚函数。因为这两个方法无需实现,测试的时候程序会走到mock出来的函数中,即使实现, 也不会被调用到。

下面通过gmock来mock(模拟)AccountManager的两个方法:

 // MockAccountManager, mock AccountManager with googlemock
class MockAccountManager : public AccountManager
{
public:
MOCK_METHOD1(findAccountForUser, Account(const std::string&)); MOCK_METHOD1(updateAccount, void(const Account&));
};

类MockAccountManager是继承数据库DB方法类AccountManager的。其中MOCK_METHOD1为gmock的宏定义。头文件中还有其他类似宏定义,如MOCK_METHOD0,MOCK_METHOD2...

MOCK_METHOD#1(#2, #3(#4) )

#2是你要mock的方法名称!#1表示你要mock的方法共有几个参数,#4是这个方法具体的参数,#3表示这个方法的返回值类型。很简单不是?!

// Account.h
// basic application data class
#pragma once #include <string> class Account
{
private:
std::string accountId; //账号 long balance; //存款 呃 还是叫余额吧 public:
Account(); Account(const std::string& accountId, long initialBalance); //消费
void debit(long amount); //收入
void credit(long amount); //获取存款
long getBalance() const; //获取账号
std::string getAccountId() const;
};

上面这个类是为了方便模拟转账业务构造的一个账户类。类Account有debit(消费)、credit(收入)、getBalance(获取存款)和getAccountId(获取账号)四个方法。

// A facility class acts as an external DB
class AccountHelper
{
private:
std::map<std::string, Account> mAccount;
// an internal map to store all Accounts for test public:
AccountHelper(std::map<std::string, Account>& mAccount); void updateAccount(const Account& account); Account findAccountForUser(const std::string& userId);
}; AccountHelper::AccountHelper(std::map<std::string, Account>& mAccount)
{
this->mAccount = mAccount;
} void AccountHelper::updateAccount(const Account& account)
{
this->mAccount[account.getAccountId()] = account;
} Account AccountHelper::findAccountForUser(const std::string& userId)
{
if (this->mAccount.find(userId) != this->mAccount.end())
return this->mAccount[userId];
else
return Account();
}

上面这个类,扮演着数据库的就角色。mock(模拟)出来的方法,都将用该类的函数替代实现。

下面,我们来写一个测试用例来看看gmock的神奇作用。

// Test case to test AccountService
TEST(AccountServiceTest, transferTest)
{
std::map<std::string, Account> mAccount;
mAccount["A"] = Account("A", );
mAccount["B"] = Account("B", );
AccountHelper helper(mAccount); MockAccountManager* pManager = new MockAccountManager(); // specify the behavior of MockAccountManager
// always invoke AccountHelper::findAccountForUser
// when AccountManager::findAccountForUser is invoked
EXPECT_CALL(*pManager, findAccountForUser(testing::_)).WillRepeatedly(
testing::Invoke(&helper, &AccountHelper::findAccountForUser)); // always invoke AccountHelper::updateAccount
//when AccountManager::updateAccount is invoked
EXPECT_CALL(*pManager, updateAccount(testing::_)).WillRepeatedly(
testing::Invoke(&helper, &AccountHelper::updateAccount)); AccountService as;
// inject the MockAccountManager object into AccountService
as.setAccountManager(pManager); // operate AccountService
as.transfer("A", "B", ); // check the balance of Account("A") and Account("B") to
//verify that AccountService has done the right job
EXPECT_EQ(, helper.findAccountForUser("A").getBalance());
EXPECT_EQ(, helper.findAccountForUser("B").getBalance()); delete pManager;
}

首先,声明一个类MockAccountManager的实例pManager,在声明一个实现类AccountHelper实例helper。EXPECT_CALL的作用是将调用pManager方法替换成实现类helper的对应方法。此处,将pManager的findAccountForUser方法替换成helper的findAccount方法,将pManager的updateAccount方法替换成helper的updateAccount方法。

最后,再用gtest的断言机制EXPECT_EQ来判断结果。

白盒测试之gmock入门篇的更多相关文章

  1. 白盒测试之JUnit与SpringTest的完美结合

    通过白盒的单元测试可以验证程序基本功能的有效性,从而保证整个系统的质量,功在一时,利在千秋.目前80%以上公司后台还是基于java,尤其是后台大量采用Spring框架,我们这里采用Junit和Spri ...

  2. 白盒测试之gtest第一个demo

    认识gtest工具后,关于它的使用,下面将用一个demo程序演示一下gtest的用法以及成果展示. 一.需要测试的C++代码: #include "myfunction.h" // ...

  3. 1. web前端开发分享-css,js入门篇

    关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人与人的教育背景与成长环境心理活动都有差别,但就别人的心得再结合自己的特点,然后探索适合自己的学 ...

  4. 浅析白盒审计中的字符编码及SQL注入

    尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范.但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如g ...

  5. web前端开发分享-css,js入门篇(转)

    转自:http://www.cnblogs.com/jikey/p/3600308.html 关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人 ...

  6. Tesseract——OCR图像识别 入门篇

    Tesseract——OCR图像识别 入门篇 最近给了我一个任务,让我研究图像识别,从我们项目的screenshot中识别文字信息,so我开始了学习,与大家分享下. 我看到目前OCR技术有很多,最主要 ...

  7. 腾讯QQ会员技术团队:人人都可以做深度学习应用:入门篇(下)

    四.经典入门demo:识别手写数字(MNIST) 常规的编程入门有"Hello world"程序,而深度学习的入门程序则是MNIST,一个识别28*28像素的图片中的手写数字的程序 ...

  8. Hadoop生态圈-大数据生态体系快速入门篇

    Hadoop生态圈-大数据生态体系快速入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.大数据概念 1>.什么是大数据 大数据(big data):是指无法在一定时间 ...

  9. web前端开发分享-css,js入门篇

    学习没有捷径,但学习是有技巧与方法.   一,css入门篇:   推荐书籍:css哪些事儿,精通css. 理由:css那些事儿,他是一本介绍css基础类的书,是入门的经典读物. 系统的介绍了css的选 ...

随机推荐

  1. sed and awk学习笔记

    sed and awk 背景 awk起源追溯至sed和grep,进而追溯至共同的行编辑器ed.实用工具grep来源于ed命令:g/re/p .实用工具awk和sed有一个共同的选项-f用于指定脚本的名 ...

  2. 不重启使XP环境变量生效

    不重启使XP环境变量生效 http://www.pkghost.cn/wz/sort0185/8874.html 在“我的电脑”->“属性”->“高级”->“环境变量”中增加或修改环 ...

  3. AE CreateFeatureClass 创建shp. 删除shp. 向shp中添加要素

    /// <summary> /// 创建多边形shp /// </summary> /// <param name="pPolygon">< ...

  4. esriFeatureType与esriGeometryType的区别与联系

    esriFeatureType通常用来表示数据的存储结构,即物理层: esriGeometryType通常用来表示数据的几何形状,即表现层. esriGeometryType枚举类型详解 常量 值 对 ...

  5. SQLite数据插入异常

    对比两条SQL语句 1.insert into MemberInfo(MTypeId,MName,MPhone,MMoney,MIsDelete) values(@tid,@name,@phone,@ ...

  6. Ossec常用命令

    启动并查看httpd服务 systemctl start httpd systemctl status httpd.service 启动并查看mysql服务 systemctl start maria ...

  7. 如何写科技文章的讨论discussion部分

    众所周知,讨论部分是在结合自己的研究结果基础上,对整个文章的结论的提炼和升华.这一部分是整个论文的精,往往点睛作用. 同时,很多杂志要求结果和讨论分开,这也就更突出了写好讨论的重要性. 那么,我们应该 ...

  8. opencv绘制灰度直方图

    代码之一: #include <cv.h> #include <highgui.h> #pragma comment( lib, "cv.lib" ) #p ...

  9. Regex Tester 安装教程

    下载com.brosinski.eclipse.regex_1.4.0.jar 地址:https://github.com/sbrosinski/RegexTester 下载之后把jar包粘贴到${e ...

  10. C/c++输入输出函数

    最全输入函数 c/c++一:c=getchar();功能:读入一个字符说明:调用此函数时要求在程序的第一行有预编译命令:#include<stdio>,不过在做c++时 有#include ...