C++、Googlemock - 测试本地对象
C++, Googlemock - testing local object
我开始使用 googletest 和 googlemock 库,但遇到无法解决的问题。我有这样的代码:
class Painter
{
public:
void DrawSomething();
};
void Painter::DrawSomething()
{
Turtle turtle;
turtle.doSomething();
}
main()
{
Painter p;
p.DrawSomething();
}
我已经模拟了 Turtle class 但是当 turtle 的对象是在本地创建时,我如何测试 doSomething() 方法(例如使用 EXPECT_CALL)?不修改Painter可以吗class?
感谢您的回答。
I have mocked the Turtle class ...
你究竟是如何嘲笑它的?
... but how can I test doSomething()
method (for example with EXPECT_CALL
) when the object of turtle is created locally?
Is it possible without modifying Painter class?
(Emphasis mine)
直截了当的答案是:否。
如果不通过接口解耦,您无法神奇地注入模拟而不是另一个 class 中使用的 真实实例 。
您应该使用类似于以下代码的代码:
struct ITurtle {
virtual void PenUp() = 0;
virtual void PenDown() = 0;
virtual void TurnLeft(double degrees) = 0;
virtual void Move(double distance) = 0;
// ...
virtual ~ITurtle() {}
};
struct TurtleMock : ITurtle {
// Mock method declarations
MOCK_METHOD0(PenUp, void ());
MOCK_METHOD0(PenDown, void ());
MOCK_METHOD1(TurnLeft, void (double));
MOCK_METHOD1(Move, void (double));
};
class Turtle : public ITurtle {
public:
void PenUp();
void PenDown();
void TurnLeft(double degrees);
void Move(double distance);
};
在单独的翻译单元中为上述声明提供真实实现。
class Painter {
public:
Painter(ITurtle& turtle) : turtle_(turtle) {}
void DrawSomething();
private:
ITurtle& turtle_;
};
void Painter::DrawSomething() {
turtle_.PenDown();
turtle_.TurnLeft(30.0);
turtle_.Move(10.0);
turtle_.TurnLeft(30.0);
turtle_.Move(10.0);
// ...
}
您也可以将 ITurtle
接口传递给 DrawSomething()
函数:
class Painter {
public:
void DrawSomething(ITurtle& turtle);
};
void Painter::DrawSomething(ITurtle& turtle) {
turtle.PenDown();
turtle.TurnLeft(30.0);
turtle.Move(10.0);
turtle.TurnLeft(30.0);
turtle.Move(10.0);
// ...
}
int main() {
NiceMock<TurtleMock> turtle;
Painter p(turtle);
// Painter p; <<< for the alternative solution
EXPECT_CALL(turtle,PenDown())
.Times(1);
EXPECT_CALL(turtle,TurnLeft(_))
.Times(2);
EXPECT_CALL(turtle,Move(_))
.Times(2);
p.DrawSomething();
// p.DrawSomething(turtle); <<< for the alternative solution
}
我已经编写了一个包装器 class 来模拟生产代码而不更改它。请让我知道这是否有任何缺陷。
#include "gtest/gtest.h"
#include "src/gtest-all.cc"
#include "src/gmock-all.cc"
#include "src/gmock_main.cc"
#include <iostream>
#include <string>
#include <vector>
using ::testing::An;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SetArgReferee;
using namespace std;
class Student
{
int iAge;
public:
Student(int _iAge) : iAge(_iAge)
{
}
virtual void PrintDetails()
{
cout<<"Age:"<<iAge<<endl;
}
virtual bool CheckGrade(int iGrade)
{
return (iGrade - 5) == iAge;
}
};
class StudentFaker
{
static Student* internalObject;
public:
static void FakerSetObject(Student* object) {
internalObject = object;
}
StudentFaker(int _iAge){
}
void PrintDetails() {
internalObject->PrintDetails();
}
bool CheckGrade(int iGrade) {
return internalObject->CheckGrade(iGrade);
}
};
Student* StudentFaker::internalObject = NULL;
class StudentMock : public Student
{
public:
StudentMock(int _iAge) : Student(_iAge) { }
MOCK_METHOD0(PrintDetails,void());
MOCK_METHOD1(CheckGrade,bool(int));
};
#define UNITTEST
bool ProductionCode();
TEST(STUDENT,TEST)
{
StudentMock stMock(8);
EXPECT_CALL(stMock, PrintDetails())
.Times(AtLeast(1))
.WillOnce(Return());
EXPECT_CALL(stMock, CheckGrade(5))
.Times(AtLeast(1))
.WillOnce(Return(true));
StudentFaker::FakerSetObject(&stMock);
EXPECT_TRUE(ProductionCode());
}
//Production code
#ifdef UNITTEST
#define Student StudentFaker
#endif
bool ProductionCode()
{
Student st(8);
st.PrintDetails();
if(st.CheckGrade(5))
return true;
else
return false;
}
//Production code
我开始使用 googletest 和 googlemock 库,但遇到无法解决的问题。我有这样的代码:
class Painter
{
public:
void DrawSomething();
};
void Painter::DrawSomething()
{
Turtle turtle;
turtle.doSomething();
}
main()
{
Painter p;
p.DrawSomething();
}
我已经模拟了 Turtle class 但是当 turtle 的对象是在本地创建时,我如何测试 doSomething() 方法(例如使用 EXPECT_CALL)?不修改Painter可以吗class?
感谢您的回答。
I have mocked the Turtle class ...
你究竟是如何嘲笑它的?
... but how can I test
doSomething()
method (for example withEXPECT_CALL
) when the object of turtle is created locally? Is it possible without modifying Painter class?
(Emphasis mine)
直截了当的答案是:否。
如果不通过接口解耦,您无法神奇地注入模拟而不是另一个 class 中使用的 真实实例 。
您应该使用类似于以下代码的代码:
struct ITurtle {
virtual void PenUp() = 0;
virtual void PenDown() = 0;
virtual void TurnLeft(double degrees) = 0;
virtual void Move(double distance) = 0;
// ...
virtual ~ITurtle() {}
};
struct TurtleMock : ITurtle {
// Mock method declarations
MOCK_METHOD0(PenUp, void ());
MOCK_METHOD0(PenDown, void ());
MOCK_METHOD1(TurnLeft, void (double));
MOCK_METHOD1(Move, void (double));
};
class Turtle : public ITurtle {
public:
void PenUp();
void PenDown();
void TurnLeft(double degrees);
void Move(double distance);
};
在单独的翻译单元中为上述声明提供真实实现。
class Painter {
public:
Painter(ITurtle& turtle) : turtle_(turtle) {}
void DrawSomething();
private:
ITurtle& turtle_;
};
void Painter::DrawSomething() {
turtle_.PenDown();
turtle_.TurnLeft(30.0);
turtle_.Move(10.0);
turtle_.TurnLeft(30.0);
turtle_.Move(10.0);
// ...
}
您也可以将 ITurtle
接口传递给 DrawSomething()
函数:
class Painter {
public:
void DrawSomething(ITurtle& turtle);
};
void Painter::DrawSomething(ITurtle& turtle) {
turtle.PenDown();
turtle.TurnLeft(30.0);
turtle.Move(10.0);
turtle.TurnLeft(30.0);
turtle.Move(10.0);
// ...
}
int main() {
NiceMock<TurtleMock> turtle;
Painter p(turtle);
// Painter p; <<< for the alternative solution
EXPECT_CALL(turtle,PenDown())
.Times(1);
EXPECT_CALL(turtle,TurnLeft(_))
.Times(2);
EXPECT_CALL(turtle,Move(_))
.Times(2);
p.DrawSomething();
// p.DrawSomething(turtle); <<< for the alternative solution
}
我已经编写了一个包装器 class 来模拟生产代码而不更改它。请让我知道这是否有任何缺陷。
#include "gtest/gtest.h"
#include "src/gtest-all.cc"
#include "src/gmock-all.cc"
#include "src/gmock_main.cc"
#include <iostream>
#include <string>
#include <vector>
using ::testing::An;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SetArgReferee;
using namespace std;
class Student
{
int iAge;
public:
Student(int _iAge) : iAge(_iAge)
{
}
virtual void PrintDetails()
{
cout<<"Age:"<<iAge<<endl;
}
virtual bool CheckGrade(int iGrade)
{
return (iGrade - 5) == iAge;
}
};
class StudentFaker
{
static Student* internalObject;
public:
static void FakerSetObject(Student* object) {
internalObject = object;
}
StudentFaker(int _iAge){
}
void PrintDetails() {
internalObject->PrintDetails();
}
bool CheckGrade(int iGrade) {
return internalObject->CheckGrade(iGrade);
}
};
Student* StudentFaker::internalObject = NULL;
class StudentMock : public Student
{
public:
StudentMock(int _iAge) : Student(_iAge) { }
MOCK_METHOD0(PrintDetails,void());
MOCK_METHOD1(CheckGrade,bool(int));
};
#define UNITTEST
bool ProductionCode();
TEST(STUDENT,TEST)
{
StudentMock stMock(8);
EXPECT_CALL(stMock, PrintDetails())
.Times(AtLeast(1))
.WillOnce(Return());
EXPECT_CALL(stMock, CheckGrade(5))
.Times(AtLeast(1))
.WillOnce(Return(true));
StudentFaker::FakerSetObject(&stMock);
EXPECT_TRUE(ProductionCode());
}
//Production code
#ifdef UNITTEST
#define Student StudentFaker
#endif
bool ProductionCode()
{
Student st(8);
st.PrintDetails();
if(st.CheckGrade(5))
return true;
else
return false;
}
//Production code