如何使用 gMock 创建模拟对象?
How do you create Mock Objects with gMock?
所以我正在尝试学习如何编写单元测试,但我偶然发现了这个问题,我不明白如何创建模拟对象。这是我的例子:
我有这个 class:
class FooChild
{
public:
void doThis();
bool doThat(int n, double x);
};
这是另一个class中的方法我想测试:
#include "FooFighter.h"
#include "FooChild.h"
void FooFighter::doSomething()
{
FooChild fooChild;
fooChild.doThis();
fooChild.doThat(4, 5);
}
我想测试它是否调用了该方法以及调用了多少次。
Google 模拟纪录片说,只有具有虚拟方法的抽象 classes 可以被模拟。这就是为什么我尝试创建 FooChild 的父级 class,如下所示:
class Foo
{
public:
virtual void doThis() = 0;
virtual bool doThat(int n, double x) = 0;
};
然后像这样创建 Foo 的模拟 class:
#include "gmock/gmock.h"
class MockFoo : public Foo
{
public:
MOCK_METHOD(void, doThis, (), (override));
MOCK_METHOD(bool, doThat, (int n, double x), (override));
};
然后我尝试为 doSomething 编写测试:
TEST_F(FooFighterTest, doSomethingTest)
{
MockFoo mock_foo
mock_foo.doThis()
.Times(1);
}
显然这行不通,我觉得我完全误解了模拟的工作原理,但我似乎找不到关于如何创建模拟的简单明了的解释。任何帮助或建议都会很棒。另外,我关于如何测试这样的 void 函数的方法可能是完全错误的,因此任何关于如何测试不 return 任何东西的函数的建议也会很棒。
除非你不把它们放在这里,否则你会遗漏很多东西。慢慢阅读googletests and specifically the mocks的文档。这就是我通常定义模拟的方式:
#include <gmock/gmock.h>
#include "Foo.hpp"
class MockFoo : public Foo {
public:
MOCK_METHOD0(doThis, void());
MOCK_METHOD2(doThat, bool(int n, double x));
};
你需要在表达式MOCK_METHOD
之后写上方法的参数个数,然后是return类型,括号之间是参数的类型。如果您不想担心此问题,请使用库中的 this nice generator。
然后在测试本身就是你定义模拟行为的地方,这就是它的重点,你可以为所有测试做一个通用的定义,或者在一些测试中改变它以不同的方式工作。
我认为写一个完整的例子没有意义,因为你有in the tutorials really good and simple ones,所以检查一下。
你的例子离工作不远了。您可能会发现阅读 gMock for Dummies 文档很有帮助。它很好地概述了基础知识。
本质上,模拟允许您对它们设定期望,并验证期望是否得到满足。您还可以执行诸如控制模拟方法的 return 值之类的操作。模拟方法必须是虚拟的,但不要求它们是抽象的。
class FooChild
{
public:
virtual void doThis() {}
virtual bool doThat(int n, double x) { return false; }
};
class MockFooChild : public FooChild
{
public:
MOCK_METHOD(void, doThis, (), (override));
MOCK_METHOD(bool, doThat, (int n, double x), (override));
};
您的示例中最大的问题是 FooFighter::doSomething
使用的是具体的(真实的)class FooChild
。您将需要一种方法将具体的 class 替换为模拟的 class(使用某种形式的依赖注入)。这是一个简单的例子:
class FooFighter
{
public:
void doSomething(FooChild &fooChild)
{
fooChild.doThis();
fooChild.doThat(4, 5);
}
};
现在您可以测试 FooFighter::doSomething
是否正在执行预期的操作:
TEST(FooFighterTest, doSomethingTest)
{
MockFooChild mockFooChild;
FooFighter fooFighter;
// doThis() must be called exactly 1 time.
EXPECT_CALL(mockFooChild, doThis).Times(Exactly(1));
// doThat() must be called exactly 1 time with parameters 4,5
EXPECT_CALL(mockFooChild, doThat(4,5)).Times(Exactly(1));
fooFighter.doSomething(mockFooChild);
}
所以我正在尝试学习如何编写单元测试,但我偶然发现了这个问题,我不明白如何创建模拟对象。这是我的例子: 我有这个 class:
class FooChild
{
public:
void doThis();
bool doThat(int n, double x);
};
这是另一个class中的方法我想测试:
#include "FooFighter.h"
#include "FooChild.h"
void FooFighter::doSomething()
{
FooChild fooChild;
fooChild.doThis();
fooChild.doThat(4, 5);
}
我想测试它是否调用了该方法以及调用了多少次。 Google 模拟纪录片说,只有具有虚拟方法的抽象 classes 可以被模拟。这就是为什么我尝试创建 FooChild 的父级 class,如下所示:
class Foo
{
public:
virtual void doThis() = 0;
virtual bool doThat(int n, double x) = 0;
};
然后像这样创建 Foo 的模拟 class:
#include "gmock/gmock.h"
class MockFoo : public Foo
{
public:
MOCK_METHOD(void, doThis, (), (override));
MOCK_METHOD(bool, doThat, (int n, double x), (override));
};
然后我尝试为 doSomething 编写测试:
TEST_F(FooFighterTest, doSomethingTest)
{
MockFoo mock_foo
mock_foo.doThis()
.Times(1);
}
显然这行不通,我觉得我完全误解了模拟的工作原理,但我似乎找不到关于如何创建模拟的简单明了的解释。任何帮助或建议都会很棒。另外,我关于如何测试这样的 void 函数的方法可能是完全错误的,因此任何关于如何测试不 return 任何东西的函数的建议也会很棒。
除非你不把它们放在这里,否则你会遗漏很多东西。慢慢阅读googletests and specifically the mocks的文档。这就是我通常定义模拟的方式:
#include <gmock/gmock.h>
#include "Foo.hpp"
class MockFoo : public Foo {
public:
MOCK_METHOD0(doThis, void());
MOCK_METHOD2(doThat, bool(int n, double x));
};
你需要在表达式MOCK_METHOD
之后写上方法的参数个数,然后是return类型,括号之间是参数的类型。如果您不想担心此问题,请使用库中的 this nice generator。
然后在测试本身就是你定义模拟行为的地方,这就是它的重点,你可以为所有测试做一个通用的定义,或者在一些测试中改变它以不同的方式工作。
我认为写一个完整的例子没有意义,因为你有in the tutorials really good and simple ones,所以检查一下。
你的例子离工作不远了。您可能会发现阅读 gMock for Dummies 文档很有帮助。它很好地概述了基础知识。
本质上,模拟允许您对它们设定期望,并验证期望是否得到满足。您还可以执行诸如控制模拟方法的 return 值之类的操作。模拟方法必须是虚拟的,但不要求它们是抽象的。
class FooChild
{
public:
virtual void doThis() {}
virtual bool doThat(int n, double x) { return false; }
};
class MockFooChild : public FooChild
{
public:
MOCK_METHOD(void, doThis, (), (override));
MOCK_METHOD(bool, doThat, (int n, double x), (override));
};
您的示例中最大的问题是 FooFighter::doSomething
使用的是具体的(真实的)class FooChild
。您将需要一种方法将具体的 class 替换为模拟的 class(使用某种形式的依赖注入)。这是一个简单的例子:
class FooFighter
{
public:
void doSomething(FooChild &fooChild)
{
fooChild.doThis();
fooChild.doThat(4, 5);
}
};
现在您可以测试 FooFighter::doSomething
是否正在执行预期的操作:
TEST(FooFighterTest, doSomethingTest)
{
MockFooChild mockFooChild;
FooFighter fooFighter;
// doThis() must be called exactly 1 time.
EXPECT_CALL(mockFooChild, doThis).Times(Exactly(1));
// doThat() must be called exactly 1 time with parameters 4,5
EXPECT_CALL(mockFooChild, doThat(4,5)).Times(Exactly(1));
fooFighter.doSomething(mockFooChild);
}