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,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