白盒测试之gmock入门篇
一、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入门篇的更多相关文章
- 白盒测试之JUnit与SpringTest的完美结合
通过白盒的单元测试可以验证程序基本功能的有效性,从而保证整个系统的质量,功在一时,利在千秋.目前80%以上公司后台还是基于java,尤其是后台大量采用Spring框架,我们这里采用Junit和Spri ...
- 白盒测试之gtest第一个demo
认识gtest工具后,关于它的使用,下面将用一个demo程序演示一下gtest的用法以及成果展示. 一.需要测试的C++代码: #include "myfunction.h" // ...
- 1. web前端开发分享-css,js入门篇
关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人与人的教育背景与成长环境心理活动都有差别,但就别人的心得再结合自己的特点,然后探索适合自己的学 ...
- 浅析白盒审计中的字符编码及SQL注入
尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范.但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如g ...
- web前端开发分享-css,js入门篇(转)
转自:http://www.cnblogs.com/jikey/p/3600308.html 关注前端这么多年,没有大的成就,就入门期间积累了不少技巧与心得,跟大家分享一下,不一定都适合每个人,毕竟人 ...
- Tesseract——OCR图像识别 入门篇
Tesseract——OCR图像识别 入门篇 最近给了我一个任务,让我研究图像识别,从我们项目的screenshot中识别文字信息,so我开始了学习,与大家分享下. 我看到目前OCR技术有很多,最主要 ...
- 腾讯QQ会员技术团队:人人都可以做深度学习应用:入门篇(下)
四.经典入门demo:识别手写数字(MNIST) 常规的编程入门有"Hello world"程序,而深度学习的入门程序则是MNIST,一个识别28*28像素的图片中的手写数字的程序 ...
- Hadoop生态圈-大数据生态体系快速入门篇
Hadoop生态圈-大数据生态体系快速入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.大数据概念 1>.什么是大数据 大数据(big data):是指无法在一定时间 ...
- web前端开发分享-css,js入门篇
学习没有捷径,但学习是有技巧与方法. 一,css入门篇: 推荐书籍:css哪些事儿,精通css. 理由:css那些事儿,他是一本介绍css基础类的书,是入门的经典读物. 系统的介绍了css的选 ...
随机推荐
- LeeCode 1-Two Sum
Two Sum Total Accepted: 125096 Total Submissions: 705262 Question Solution Given an array of integer ...
- lintcode:在二叉查找树中插入节点
题目: 在二叉查找树中插入节点 给定一棵二叉查找树和一个新的树节点,将节点插入到树中. 你需要保证该树仍然是一棵二叉查找树. 样例 给出如下一棵二叉查找树,在插入节点6之后这棵二叉查找树可以是这样 ...
- PHP中的多态
多态的概念一般是强类型语言来谈的,因为强类型语言它必须要声明参数类型,比如一个手电筒对象的打开方法其参数申明了只能是蓝光,就不能传其他光.但可以用父类渲染的方式使其多态,比如声明一个光的父类,让其它颜 ...
- java socket知识点
3.用线程池实现TCP服务器端时,首先创建一个ServerSocket实例,然后创建N个线程,每个线程反复循环,从(共享的)ServerSocket实例接收客户端连接.当多个线程同时调用一个Serve ...
- Hibernate逍遥游记-第4章映射对象标识符-increment、identity、hilo、native、assigned、sequence、<meta>
1. package mypack; import java.lang.reflect.Constructor; import org.hibernate.*; import org.hibernat ...
- PCL—低层次视觉—点云分割(基于凹凸性)
1.图像分割的两条思路 场景分割时机器视觉中的重要任务,尤其对家庭机器人而言,优秀的场景分割算法是实现复杂功能的基础.但是大家搞了几十年也还没搞定——不是我说的,是接下来要介绍的这篇论文说的.图像分割 ...
- PHP程序员的40点陋习
1.不写注释 2.不使用可以提高生产效率的IDE工具 3.不使用版本控制 4.不按照编程规范写代码 5.不使用统一的方法 6.编码前不去思考和计划 7.在执行sql前不执行编码和安全检测 8.不使用测 ...
- i386 和amd64 的意思
首先可以简化一个概念,i386=Intel 80386.其实i386通常被用来作为对Intel(英特尔)32位微处理器的统称. Windows NT类系统的安装盘上,通常i386是其根上的一个文件夹, ...
- C# Index 定义索---引具体使用2
窗体代码 using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;usi ...
- Bug调试
iPhone开发笔记——Xcode升级后的警告.错误的解决办法(一) http://blog.sina.com.cn/s/blog_58af95150101slit.html iPhone开发笔记—— ...