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