如何使用 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);
}