`
russelltao
  • 浏览: 158351 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

用google mock模拟C++对象

 
阅读更多

google mock是用来配合google test对C++项目做单元测试的。它依赖于googletest(参见我上篇文章《如何用googletest写单元测试》:http://blog.csdn.net/russell_tao/article/details/7333226),下面我来说说linux上怎么用它来做单元测试。

本文包括:1、如何获取、编译google mock;2、如何使用gmock(下面用gmock来代称google mock)配合gtest做单元测试。


1、如何获取、编译google mock

gmock的当前版本与gtest一样,是1.6.0。可以从这个网址获取:http://code.google.com/p/googlemock/downloads/list

下载到压缩包解压后,下面我们开始编译出静态库文件(必须得自己编译出),以在我们自己的单元测试工程中使用。

与gtest相同,我们执行完./configure; make后,不能执行make install,理由与上篇相同。

验证这个包有没有问题,依然可以执行如下命令:

cd make
make
./gmock_test

如果你看到类似下文的输出屏幕,证明你的机器运行gmock没有问题。

[----------] Global test environment tear-down
[==========] 13 tests from 3 test cases ran. (2 ms total)
[  PASSED  ] 13 tests.

这时还没有编译出我们要的libgmock.a呢。继续在gmock解包目录下执行:

g++ -I gtest/include/ -I gtest/ -I include/ -I ./ -c gtest/src/gtest-all.cc 
g++ -I gtest/include/ -I gtest/ -I include/ -I ./ -c src/gmock-all.cc       
ar -rv libgmock.a gtest-all.o gmock-all.o 

如此,当前目录下会链接出我们需要的libgmock.a。注意,这个gmock.a静态库里,把gtest需要的gtest-all.cc都编译进来了,所以我们的单元测试工程只需要链接libgmock,不再需要链接上文说的libgtest了。


2、如何使用gmock

首先,编译我们自己的单元测试工程时,需要在makefile里加入以下编译选项:-I${GTEST_DIR}/include -I${GMOCK_DIR}/include,这两个目录我们自己从上面的包里拷贝出来即可。链接时,需要加上libgmock.a。


还是以一个例子来说明怎么在mock对象的情况下写单元测试。


我现在有一个生产者消费者网络模型,消费者(例如client)会先发TCP请求到我的SERVER去订阅某个对象。生产者(另一台SERVER)产生关于某个对象的事件后发给我的SERVER后,我的SERVER再把事件发给消费者。

就是这么简单。


我现在想写一个单元测试,主要测试代码逻辑,不想去管网络包的收发这些事情。

我现在有两个类,一个叫CSubscriber,它封装为一个订阅的消费者,功能主要是操作网络,包括网络收发包,协议解析等。另一个叫CSubEventHandler,它主要做逻辑处理,去操作CSubscriber对象,例如epoll返回读事件后,会构造一个CSubscriber对象,然后CSubEventHandler::handleRead方法就来处理这个CSubscriber对象。


我单元测试的目的是,测试CSubEventHandler::handleRead的业务逻辑,我同时也想测试CSubscriber方法里的协议解析逻辑,但是对于CSubscriber封装的读写包部分,我希望可以mock成我想要的网络包。

怎么做呢?

a)、先mock一个CSubscriber类如下:

class MockCSubscriber : public CSubscriber
{
public:
	MockCSubscriber(int fd):CSubscriber(fd){}
	MOCK_METHOD1(readBuf, int(int len));
	MOCK_METHOD1(writeBuf, int(int len));
	MOCK_METHOD0(closeSock, void());
};

其中,CSubscriber的构造方法必须有一个int型的fd,而readBuf和writeBuf都只接收一个int型的参数,而closeSock方法 没有参数传递。于是我使用了MOCK_METHOD0和MOCK_METHOD1这两个宏来声明想MOCK的方法。这两个宏的使用很简单,解释下:

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

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

很简单不是?!


b)、如果只关心mock方法的返回值。

这里用到一个宏ON_CALL。看例子:

ON_CALL(subObj, readBuf(1000)).WillByDefault(Return(blen));

什么意思呢?再用刚才的解释方法:

ON_CALL(#1, #2(#3)).WillByDefault(Return(#4));

#1表示mock对象。就像我上面所说,对CSubscriber我定义了一个Mock类,那么就必须生成相应的mock对象,例如:

MockCSubscriber subObj(5);

#2表示想定义的那个方法名称。上例中我想定义readBuf这个方法的返回值。

#3表示readBuf方法的参数。这里的1000表示,只有调用CSubscriber::readBuf同时传递参数为1000时,才会用到ON_CALL的定义。

#4表示调用CSubscriber::readBuf同时传递参数为1000时,返回blen这个变量的值。


c)、如果还希望mock方法有固定的被调用方式

这里用到宏EXPECT_CALL,看个例子:

EXPECT_CALL(subObj, readBuf(1000)).Times(1);

很相似吧?最后的Times表示,只希望readBuf在传递参数为1000时,被调用且仅被调用一次。


其实这些宏有很复杂的用法的,例如:

EXPECT_CALL(subObj, readBuf(1000))
    .Times(5)
    .WillOnce(Return(100))
    .WillOnce(Return(150))
    .WillRepeatedly(Return(200));

表示,readBuf希望被调用五次,第一次返回100,第二次返回150,后三次返回200。如果不满足,会报错。


d)、实际的调用测试

其实调用跟上篇googletest文章里的测试是一致的,我这里只列下上文的完整用例代码(不包括被测试类的实现代码):

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "CSubscriber.h"
#include "CPublisher.h"
#include "CSubEventHandler.h"
#include "CPubEventHandler.h"

using ::testing::AtLeast;
using testing::Return;


class MockCSubscriber : public CSubscriber
{
public:
	MockCSubscriber(int fd):CSubscriber(fd){}
	MOCK_METHOD1(readBuf, int(int len));
	MOCK_METHOD1(writeBuf, int(int len));
	MOCK_METHOD0(closeSock, void());
};

class MockCPublisher : public CPublisher
{
public:
	MockCPublisher(int fd):CPublisher(fd){}
	MOCK_METHOD1(readBuf, int(int len));
	MOCK_METHOD1(writeBuf, int(int len));
	MOCK_METHOD0(closeSock, void());
};


TEST(subpubHandler, sub1pub1) {
	MockCSubscriber subObj(5);
	MockCPublisher pubObj(5);

	subObj.m_iRecvBufLen = 1000;
	pubObj.m_iRecvBufLen = 1000;

	char* pSubscribeBuf = "GET / HTTP/1.1\r\nobject: /tt/aa\r\ntime: 112\r\n\r\n";
	char* pMessageBuf = "GET / HTTP/1.1\r\nobject: /tt/aa\r\ntime: 112\r\nmessage: tttt\r\n\r\n";
	subObj.m_pRecvBuf = pSubscribeBuf;
	int blen = strlen(pSubscribeBuf);
	subObj.m_iRecvPos = blen;

	pubObj.m_pRecvBuf = pMessageBuf;
	int mlen = strlen(pMessageBuf);
	pubObj.m_iRecvPos = mlen;


	ON_CALL(subObj, readBuf(1000)).WillByDefault(Return(blen));
	ON_CALL(subObj, writeBuf(CEventHandler::InternalError.size())).WillByDefault(Return(0));

	CSubEventHandler subHandler(NULL);
	CPubEventHandler pubHandler(NULL);

	CHashTable ht1(100);
	CHashTable ht2(100);
	subHandler.initial(100, &ht1, &ht2);
	pubHandler.initial(100, &ht1, &ht2);

	EXPECT_CALL(subObj, readBuf(1000)).Times(1);
	//EXPECT_CALL(subObj, closeSock()).Times(1);
	EXPECT_CALL(subObj, writeBuf(4)).Times(1);

	EXPECT_TRUE(subHandler.handleRead(&subObj));

	ON_CALL(pubObj, readBuf(1000)).WillByDefault(Return(mlen));
	ON_CALL(pubObj, writeBuf(4)).WillByDefault(Return(0));

	EXPECT_CALL(pubObj, readBuf(1000)).Times(1);
	EXPECT_CALL(pubObj, closeSock()).Times(1);
	EXPECT_CALL(pubObj, writeBuf(CEventHandler::Success.size())).Times(1);

	EXPECT_TRUE(pubHandler.handleRead(&pubObj));
}

CSubscriber的头文件:

class CSubscriber : public CBaseConnection, public CHashElement
{
public:
	CSubscriber(int fd);
	
	virtual ~CSubscriber();

	bool initial();

	bool reset();

	//function return:
	//0: means complete read, all elements parsed OK
	//1: means it need recv more buf, not it's not complete
	//-1: means the packet is not valid.
	//-2: means connection wrong.
	int readPacket();

	//max send buf length
	static int m_iSendBufLen;

	//max recv buf length
	static int m_iRecvBufLen;

private:
	/*request format:
	 * GET /objectname?ts=xxx HTTP/1.x\r\n\r\n*/
	bool parsePacket();
};


e)、main函数的写法

与gtest相同,唯一的区别是初始化参数,如下:

#include <gmock/gmock.h>

int main(int argc, char** argv) {
	testing::InitGoogleMock(&argc, argv);
	//testing::InitGoogleTest(&argc, argv);

	// Runs all tests using Google Test.
	return RUN_ALL_TESTS();
}

如此,就可以完整的使用googletest/googlemock做C++工程的单元测试了,确实很简单好用。

分享到:
评论

相关推荐

    google c++ testing 框架 google mock 资料搜集

    Google Mock(通常称为gmock)是Google Test框架的一部分,专门用于创建和使用模拟对象,以便在测试中隔离被测试代码,确保其独立于其他组件进行评估。下面,我们将深入探讨这两个重要的测试工具及其应用。 **...

    转:google mock C++单元测试框架-奋飞的菜鸟-ChinaUnix博客1

    Google Mock 是一个强大的 C++ 单元测试框架,它允许开发者创建模拟对象(Mock Objects)以测试复杂的系统中各个组件的交互。Mock 对象能够模拟真实对象的行为,并且可以预设它们在特定调用下的响应,这对于隔离测试...

    googlemock

    GoogleMock 是一个强大的单元测试框架,它扩展了GoogleTest,专为C++程序员设计,用于创建和执行模拟对象,以方便进行单元测试。在本文中,我们将深入探讨GoogleMock的基本概念、用途、安装过程以及如何在项目中使用...

    googlemock资料

    在C++编程中,Google Mock(通常简称为gmock)是Google开发的一个工具,允许开发者编写模拟对象来代替实际的对象,以便在测试过程中隔离被测代码。这个压缩包文件包含了与学习和使用Google Mock相关的资料,特别是从...

    google mock 源代码 欢迎有需要的朋友下载

    谷歌Mock(Google Mock)是Google开发的一个开源框架,主要用于C++单元测试,它允许开发者创建模拟对象以测试复杂的系统。这个框架是Google Test的一部分,提供了一种强大的方式来设计和执行针对类方法的期望和行为...

    googlemock库附使用教程

    Google Mock(也称为gmock)是Google开源的一个强大工具,专门用于编写C++的模拟对象,配合Google Test(gtest)框架进行单元测试。本文将详细介绍如何利用Google Mock进行单元测试,以及如何设置开发环境和编写测试...

    Google C++ Mock框架 googlemock使用介绍

     给大家介绍在测试中使用的利器googlemock,它是Google在2008年发布的一套针对C++的Mock框架,与googletest吸取JUnit的精华一样,的它灵感同样来自去Java社区的JMock、EasyMock等Mock思想。  更多关于google...

    google mock cookbook 中译本

    Google Mock是一个基于C++的测试框架,它用于创建和使用模拟对象,以及检查、诊断和指定复杂的C++接口。 知识点一:Google Mock的命名空间和可读性 在使用Google Mock时,所有的模拟函数定义都位于testing命名空间...

    Mockpp使用方法简介

    ChainableMockObject 是一个链式的 Mock 对象,它允许开发者使用链式调用来模拟复杂的行为。 四、访问内部对象 Mockpp 提供了多种方法来访问内部对象,包括使用 VisitableMockObject 和 ChainableMockObject 等。 ...

    C-Mock:C Mock是Google Mock的扩展,允许函数模拟

    C Mock-Google Mock扩展 概述 C Mock是的扩展,允许函数。 仅支持全局(非静态)函数模拟。 这既不是Google Mock的补丁,也不是它的分支。...C Mock不知道是否使用名称修饰声明了模拟函数-这是纯C函数还是C ++

    Google Mock For Dummies / GMock 傻瓜书

    Google C++ Mocking Framework(简称 GMock)是一个强大的工具,用于帮助开发者创建和管理 C++ 语言中的 mock 对象。在软件开发过程中,特别是在单元测试阶段,我们常常需要模拟(mock)某些组件的行为来隔离测试...

    googleTest和googleMock,可以在vs2017、vs2010中编译

    Google Mock(简称gmock)是Google在2008年推出的一套针对C++的Mock框架,它灵感取自于jMock、EasyMock、harcreat。它提供了以下这些特性:轻松地创建mock类支持丰富的匹配器(Matcher)和行为(Action)支持有序、...

    glmock:使用 GoogleMock 的 Opengl 模拟

    它使用 GoogleMock 来模拟 opengl。 先决条件: OpenGL 谷歌模拟 谷歌测试 建造: mkdir build cd build cmake ../ make 用法: #include "glmock.hpp" TEST(ShaderLoaderTest, load_shader_from_file) { ...

    C++开发测试工具gmock1.8.1.rar

    gmock提供了一种强大的方式来模拟C++类的行为,使得在编写单元测试时可以独立于实际的依赖对象进行操作。在gmock 1.8.1版本中,它依然支持那些不完全兼容C++11标准的编译器,这对于那些仍在使用较旧编译器的开发者来...

    Google C++ Mocking Framework Cheat Sheet

    Google C++ Mocking Framework,通常简称为gMock,是Google为C++开发的一个强大的单元测试框架,主要用于创建模拟对象(Mock Objects)。它能够帮助开发者在不依赖实际对象的情况下测试代码,从而简化测试过程并提高...

    C++开发测试工具gmock使用详解(进阶Demo).rar

    gmock全称为Google Mock,它是Google C++测试框架Google Test(gtest)的一部分,专注于模拟对象的创建和行为。通过gmock,开发者可以定义对象的行为,并检查这些对象在测试过程中如何被调用,以及它们的方法是否按...

    GMock——groovy下的mock工具

    GMock 是 Google 推出的一款强大的 C++ 测试框架 Google Test(GTest)的一部分,但在这里我们讨论的是它在 Groovy 语言环境中的应用。 Groovy 是一种基于 JVM 的动态编程语言,与 Java 兼容,但语法更加简洁和灵活...

    double:Rust的模拟框架-受googlemock启发

    Google Mock,是Google开发的一个C++测试库,它提供了一种强大的方式来创建和配置模拟对象。GMock支持定义期望(Expectations),这些期望定义了模拟对象在特定调用时应该如何表现。例如,你可以设置一个期望,当...

Global site tag (gtag.js) - Google Analytics