gmock

gtest實際上是googlemock(簡稱gmock)的一個模塊,gmock的下載包中包含gtest。gmock的主頁爲:http://code.google.com/p/googlemock/ios

三篇學習文章:數組

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

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

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:對返回值打樁google

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


示例3:將調用代理給一個fake對象spa


示例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

相關文章
相關標籤/搜索