Use Google mock to simulate C ++ objects

Source: Internet
Author: User

Google mock is used in combination with Google test to perform unit tests on C ++ projects. It depends on googletest (see my previous article "How to Write unit tests with googletest: http://blog.csdn.net/russell_tao/article/details/7333226). Below I'll talk about how to use it for unit tests on Linux.

This article includes: 1. How to obtain and compile Google mock; 2. How to Use gmock (hereinafter referred to as Google mock) and gtest for unit testing.

1. How to obtain and compile Google mock

The current version of gmock is 1.6.0, which is the same as that of gtest. You can obtain the URL http://code.google.com/p/googlemock/downloads/list.

After downloading to the compressed package and decompressing it, we will compile the static library file (which must be compiled by ourselves) for use in our unit test project.

Like gtest, make install cannot be executed after./configure; make is executed. The reason is the same as that in the previous article.

To verify whether the package is correct, run the following command:

cd makemake./gmock_test

If you see an output screen similar to the following, it proves that your machine is running gmock.

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

At this time, we have not compiled libgmock.. Run the following command in the gmock unpack directory:

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 

In this way, libgmock. A is linked to the current directory. Note that this gmock. A static library, gtest needs to be compiled in the gtest-all.cc, so our unit test project only need to link libgmock, no longer need to link the above libgtest.

2. How to Use gmock

First, when compiling our own unit test project, add the following compilation options to makefile:-I $ {gtest_dir}/include-I $ {gmock_dir}/include, we can copy these two directories from the above package. Libgmock. A must be added to the link.

Let's take an example to illustrate how to write a unit test with a mock object.

I now have a producer consumer network model. A consumer (such as a client) sends a TCP request to my server to subscribe to an object. After the producer (another server) generates an event about an object and sends it to the server, the server sends the event to the consumer.

That's simple.

I want to write a unit test to test the code logic. I don't want to worry about sending and receiving network packets.

I now have two classes: csubscriber, which is encapsulated as a subscription consumer. The main function is to operate the network, including sending and receiving packets and Protocol parsing. The other name is csubeventhandler, which is mainly used for logic processing to operate csubscriber objects. For example, after epoll returns a read event, it constructs a csubscriber object and then csubeventhandler :: the handleread method is used to process the csubscriber object.

The purpose of my unit test is to test the business logic of csubeventhandler: handleread. I also want to test the Protocol parsing logic in the csubscriber method, but for the read/write package encapsulated by csubscriber, I want to use mock as the desired Network Package.

How can this problem be solved?

A) First mock A csubscriber class as follows:

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());};

The csubscriber constructor must have an int type FD, while both readbuf and writebuf receive only one int type parameter, while the closesock method does not have a parameter to pass. So I used the mock_method0 and mock_method1 macros to declare the mock method. The use of these two macros is very simple:

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

#2 is the mock method name! #1 indicates that the mock method requires several parameters. #4 indicates the specific parameters of the method. #3 indicates the type of the return value of the method.

It's easy, isn't it ?!

B) If you only care about the return value of the mock method.

A macro on_call is used here. Example:

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

What does it mean? Use the preceding explanation:

On_call (#1, #2 (#3). willbydefault (Return (#4 ));

#1 indicates the mock object. As I mentioned above, if I have defined a mock class for csubscriber, the corresponding mock object must be generated, for example:

MockCSubscriber subObj(5);

#2 indicates the name of the method to be defined. In the above example, I want to define the returned value of the readbuf method.

#3 indicates the parameters of the readbuf method. Here, 1000 indicates that the on_call definition is used only when csubscriber: readbuf is called and the parameter is passed as 1000.

#4 indicates that the value of blen is returned when the call csubscriber: readbuf is passed with the parameter 1000.

C) if you want a fixed mock method to be called

The macro expect_call is used here. Let's look at an example:

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

Very similar, right? The last times indicates that only readbuf is called once when the parameter is passed as 1000.

In fact, these macros have complicated usage, such:

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

Indicates that readbuf is expected to be called five times, 100 is returned for the first time, 150 is returned for the second time, and 200 is returned for the third time. If not, an error is returned.

D) actual call Test

In fact, the call is consistent with the test in the previous googletest article. Here I only list the complete Use Case code (excluding the implementation code of the tested class ):

#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 header file:

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 lengthstatic int m_iSendBufLen;//max recv buf lengthstatic int m_iRecvBufLen;private:/*request format: * GET /objectname?ts=xxx HTTP/1.x\r\n\r\n*/bool parsePacket();};

E) write the main function

Same as gtest, the only difference is that the initialization parameters are as follows:

#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();}

In this way, you can use googletest/googlemock to complete the unit test of the C ++ project, which is really easy to use.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.