gmock

来源:互联网 发布:qq邮箱下载电脑版mac 编辑:程序博客网 时间:2024/05/22 07:41

gtest其实是googlemock(简称gmock)的一个模块,gmock的下载包中包含gtest。gmock的主页为:http://code.google.com/p/googlemock/

三篇学习文章:

1,http://code.google.com/p/googlemock/wiki/ForDummies

2,http://code.google.com/p/googlemock/wiki/CheatSheet

3,http://code.google.com/p/googlemock/wiki/CookBook

按上述顺序阅读,最后一篇文章比较长。


示例1:基本功能

// ITurtle.h
#ifndef __I_TURTLE_H__
#define __I_TURTLE_H__


class ITurtle
{
public:
    virtual ~ITurtle() {}


    virtual void PenUp() = 0; 
    virtual void PenDown() = 0;
    virtual void Forward(int distance) = 0;
    virtual void TurnRight(int degrees) = 0; // 顺时针旋转一定的角度
    virtual void GoTo(int x, int y) = 0;
    virtual int GetX() const = 0;
    virtual int GetY() const = 0;
};


#endif // __I_TURTLE_H__


// Painter.h
#ifndef __PAINTER_H__
#define __PAINTER_H__


#include "ITurtle.h"


class CPainter
{
private: 
    ITurtle* m_poTurtle; 


public:
    CPainter();
    virtual ~CPainter();


    void SetTurtle(ITurtle* pTl);
    void DrawSquare(int i32Width); //画正方形  
    void DrawCircle();
}; 


#endif // __PAINTER_H__


// Painter.cpp
#include "stdafx.h"
#include "Painter.h"


CPainter::CPainter()
{
    m_poTurtle = NULL;



CPainter::~CPainter()
{


}


void CPainter::SetTurtle(ITurtle* poTurtle)

    m_poTurtle = poTurtle; 



void CPainter::DrawSquare(int i32Width)

    if ((!m_poTurtle) || (i32Width <= 0)) 
    {
        return; 
    }


    m_poTurtle->PenDown(); 
    m_poTurtle->Forward(i32Width); 
    m_poTurtle->TurnRight(90); 
    m_poTurtle->Forward(i32Width); 
    m_poTurtle->TurnRight(90); 
    m_poTurtle->Forward(i32Width); 
    m_poTurtle->TurnRight(90); 
    m_poTurtle->Forward(i32Width); 
    m_poTurtle->TurnRight(90); 
    m_poTurtle->PenUp(); 
}


// MockTurtle.h
#ifndef __MOCK_TURTLE_H__
#define __MOCK_TURTLE_H__


#include "gmock/gmock.h"
#include "ITurtle.h"


class MockTurtle : public ITurtle
{
private:
    int m_i32Data; // 随便写的,不重要


public:
    MockTurtle(int i32Data)
    {
        m_i32Data = i32Data;
    }


    void SetData(int i32Data)
    {
        m_i32Data = i32Data;
    }


    int GetData()
    {
        return m_i32Data;
    }


    MOCK_METHOD0(PenUp, void());
    MOCK_METHOD0(PenDown, void());
    MOCK_METHOD1(Forward, void(int distance));
    MOCK_METHOD1(TurnRight, void(int degrees));
    MOCK_METHOD2(GoTo, void(int x, int y));
    MOCK_CONST_METHOD0(GetX, int());
    MOCK_CONST_METHOD0(GetY, int());
};


#endif // __MOCK_TURTLE_H__


// PainterTest.h
#ifndef __PAINTER_TEST_H__
#define __PAINTER_TEST_H__


#include "gtest/gtest.h"


class CPainterTest : public testing::Test
{
public:
    CPainterTest();
    virtual ~CPainterTest();


    void DrawSquareTest001();
};


#endif // __PAINTER_TEST_H__


// PainterTest.cpp
#include "stdafx.h"
#include "PainterTest.h"
#include "Painter.h"
#include "MockTurtle.h"


using testing::AtLeast; 
using testing::Return; 
using testing::_; 
using testing::Gt; 
using testing::Eq;  


CPainterTest::CPainterTest()
{


}


CPainterTest::~CPainterTest()
{


}


void CPainterTest::DrawSquareTest001()
{
    MockTurtle oMockTurtle(0);


    // 下面两句的意思是:预计调用完四次参数大于0的Forward()以后,Forward()将不会再被调用。
    // 注意是倒序的,后面的expect先满足
    EXPECT_CALL(oMockTurtle, Forward(_)) 
        .Times(0); 
    EXPECT_CALL(oMockTurtle, Forward(Gt(0))) 
        .Times(4); 


    // 预计将会调用四次TurnRight(90)
    EXPECT_CALL(oMockTurtle, TurnRight(90)) 
        .Times(4); 


    // 应该会调用PenUp和PenDown,各一次(这里没有写Times,gmock会自动推导)
    EXPECT_CALL(oMockTurtle, PenUp()); 
    EXPECT_CALL(oMockTurtle, PenDown()); 


    // 开始调用
    CPainter oPainter; 
    oPainter.SetTurtle(&oMockTurtle); 


    // 测试输入10的情况,应该会调用四次Forward(10)和四次Turn(90) 
    oPainter.DrawSquare(10);


    // 测试输入0的情况,应该不会调用Forward才对 
    oPainter.DrawSquare(0);  
}


TEST_F(CPainterTest, DrawSquareTest001) 
{
    DrawSquareTest001();
}


// main.cpp
#include "stdafx.h"
#include "gmock/gmock.h"


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


    system("pause");
    return 0;
}

示例2:对返回值打桩

// DVariantField.h
#ifndef D_VARIANT_FIELD_H_
#define D_VARIANT_FIELD_H_


namespace seamless
{
    union UVariantField
    {
        char* m_szVal;
        int m_i32Val;
    };
} // namespace seamless


#endif // D_VARIANT_FIELD_H_


// IParam.h
#ifndef I_PARAM_H_
#define I_PARAM_H_


#include "DVariantField.h"


namespace seamless
{
    class IParam
    {
    public:
        virtual ~IParam() {}


    public:
        virtual int GetParam(const char* pszName, UVariantField*& rpunValue) = 0;
    };
} // namespace seamless


#endif // I_PARAM_H_


// IAPIProvider.h
#ifndef I_API_PROVIDER_H_
#define I_API_PROVIDER_H_


#include "IParam.h"


namespace seamless
{
    class IAPIProvider
    {
    public:
        virtual ~IAPIProvider() {}


    public:
        virtual IParam* GetParamIF() = 0; // IF = interface
    };
} // namespace seamless


#endif // I_API_PROVIDER_H_


// Rank.h
#ifndef RANK_H_
#define RANK_H_


#include "IAPIProvider.h"


namespace seamless
{
    class Rank
    {
    public:
        virtual ~Rank() {}


    public:
        void ProcessQuery(IAPIProvider* poAPIProviderIF);
    };
} // namespace seamless


#endif // RANK_H_


// Rank.cpp
#include "stdafx.h"
#include <iostream>
#include "IAPIProvider.h"
#include "Rank.h"


using namespace std;


namespace seamless
{
    void Rank::ProcessQuery(IAPIProvider* poAPIProviderIF)
    {
        IParam* poParamIF = poAPIProviderIF->GetParamIF();
        if (!poParamIF)
        {
            cerr << "parameter interface is NULL" << endl;
            return;
        }


        bool bIsRetailWholesale = 0;
        int bIsUseAlipay = 0;


        UVariantField* punValue = new UVariantField;


        poParamIF->GetParam("retail_wholesale", punValue);
        bIsRetailWholesale = (0 == strcmp(punValue->m_szVal, "0")) ? false : true;


        poParamIF->GetParam("use_alipay", punValue);
        bIsUseAlipay = (0 == strcmp(punValue->m_szVal, "0")) ? false : true;


        cout << "Is Retail Wholesale: " << bIsRetailWholesale << endl;
        cout << "Is Use Alipay: " << bIsUseAlipay << endl;


        delete punValue;
    }
} // namespace seamless


// MockParamIF.h
#ifndef MOCK_PARAM_IF_H_
#define MOCK_PARAM_IF_H_


#include "gmock/gmock.h"
#include "IParam.h"


namespace seamless
{
    class CMockParamIF : public IParam
    {
    public:
        MOCK_METHOD2(GetParam, int(const char* pszName, UVariantField*& rpunValue));
    };
} // namespace seamless


#endif // MOCK_PARAM_IF_H_


// MockAPIProviderIF.h
#ifndef MOCK_API_PRROVIDER_IF_H_
#define MOCK_API_PRROVIDER_IF_H_


#include "gmock/gmock.h"
#include "IAPIProvider.h"


namespace seamless
{
    class CMockAPIProviderIF : public IAPIProvider
    {
    public:
        MOCK_METHOD0(GetParamIF, IParam*());
    };
} // namespace seamless


#endif // MOCK_API_PRROVIDER_IF_H_


// RankTest.cpp
#include "stdafx.h"
#include "MockAPIProviderIF.h"
#include "MockParamIF.h"
#include "Rank.h"


using namespace seamless;


using ::testing::_;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;


void Test001()
{
    CMockAPIProviderIF* poMockAPIProvider = new CMockAPIProviderIF;
    CMockParamIF* poMockParamIF = new CMockParamIF;


    EXPECT_CALL(*poMockAPIProvider, GetParamIF())
        .Times(AtLeast(1))
        .WillRepeatedly(Return(poMockParamIF)); // 这里就是对返回值打桩,如果不指定,则返回默认的(返回值为整型的函数默认返回0,为布尔型的默认返回false,为指针的默认返回NULL)


    UVariantField unRetailWholesaleValue;
    unRetailWholesaleValue.m_szVal = "0";


    UVariantField unDefaultValue;
    unDefaultValue.m_szVal = "9";


    EXPECT_CALL(*poMockParamIF, GetParam(_, _))
        .Times(AtLeast(1))
        .WillOnce(DoAll(SetArgPointee<1>(unRetailWholesaleValue), Return(1))) // 这些语法参考学习文章或者下面的“设置参数示例”
        .WillRepeatedly(DoAll(SetArgPointee<1>(unDefaultValue), Return(1)));


    Rank oRank;
    oRank.ProcessQuery(poMockAPIProvider);


    delete poMockAPIProvider;
    delete poMockParamIF;
}


TEST(RankTest, Test001)
{
    Test001();
}


示例3:将调用代理给一个fake对象


示例4:对时间函数打桩,如对时间函数time_t的封装GetEpochTime()打桩

    CMockTimeAPI oMockTimeAPI;

    EXPECT_CALL(oMockTimeAPI, GetEpochTime())
        .Times(3)
        .WillOnce(Return(1))
        .WillOnce(Return(2))
        .WillOnce(Return(3));

预期调用三次,第一次返回1,第二次返回2,第三次返回3。

示例5:设置参数(引用、指针类型的出参,数组类型的出参),指的是出参,相当于返回值的角色
设置引用类型的参数是通过SetArgReferee<N>(value)实现的,N是参数的索引,从0开始。这个东西称为Action,类似的Action还有SetArgPointee<N>(value),设置指针参数, SetArrayArgument<N>(first, last),设置数组参数,数组范围[first,last),前闭后开。例如:
class XXXClient {
public:
    virtual void QueryXXX(const Request&, Response&) = 0;
};

class XXXClientMock : public XXXClient
{
public:
    MOCK_METHOD2(QueryXXX, QueryResult (Request&, Response&));
};

void Test()
{
    XXXCLientMock oMock;
 
    // 设计一个期望的oRsp返回对象
    Response oRsp;
    // ...


    EXPECT_CALL(oMock,  QueryXXX(_, _)).
        WillOnce(SetArgReferee<1>(oRsp));


    // ...
}

有时候,可能需要设置参数和返回值,也就是同时设置多个行为,那么可以使用DoAll函数帮我们实现,DoAll相当于一个action的集合,使用示例如下:
EXPECT_CALL(oMock,  QueryXXX(_, _)).
    WillOnce(DoAll(SetArgReferee<1>(oRsp), Return(someObj))));

// SetArrayArgument<N>(first, last)示例:
SetArrayArgument<N>(first, last)    
Copies the elements in source range [first, last) to the array pointed to by the N-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.

示例:
using ::testing::NotNull;
using ::testing::SetArrayArgument;

class MockArrayMutator : public ArrayMutator {
 public:
  MOCK_METHOD2(Mutate, void(int* values, int num_values));
  ...
};
...

  MockArrayMutator mutator;
  int values[5] = { 1, 2, 3, 4, 5 };
  EXPECT_CALL(mutator, Mutate(NotNull(), 5))
      .WillOnce(SetArrayArgument<0>(values, values + 5)); // 将数组元素[values[0], values[5])拷贝到函数Mutate的第0个参数中,作为出参。



注意:

1,mock函数必须为虚函数,因为要被mock对象重载。(不一定非要是纯虚函数)

2,可以只mock感兴趣的接口,不感兴趣的会继承父类中的实现,即:

class IAbc
{
public:
    virtual bool Func1() = 0;


    virtual int Func2() { return 100; }
};

class CMockAbc : public IAbc
{
public:
    MOCK_METHOD0(Func1, int());
};

通过mock对象调用Func2时,会使用父类中的实现,返回100


原创粉丝点击