【问题标题】:How do you create Mock Objects with gMock?如何使用 gMock 创建 Mock 对象?
【发布时间】:2020-03-04 07:52:25
【问题描述】:

所以我正在尝试学习如何编写单元测试,但我偶然发现了这个问题,我不明白如何创建模拟对象。这是我的例子: 我有这门课:

class FooChild
{
public:
    void doThis();
    bool doThat(int n, double x);
};

这是我要测试的另一个类中的方法:

#include "FooFighter.h"
#include "FooChild.h"

void FooFighter::doSomething()
{
    FooChild fooChild;
    fooChild.doThis();
    fooChild.doThat(4, 5);
}

我想测试它是否调用了该方法以及调用了多少次。 谷歌模拟纪录片说,只有具有虚拟方法的抽象类才能被模拟。这就是为什么我尝试创建 FooChild 的父类,如下所示:

class Foo
{
public:
    virtual void doThis() = 0;
    virtual bool doThat(int n, double x) = 0;
};

然后像这样创建一个 Foo 的模拟类:

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

显然这不起作用,我感觉我完全误解了 mock 的工作原理,但我似乎无法找到一个关于如何创建 mock 的简单明了的解释。任何帮助或建议都会很棒。此外,我关于如何测试这样的 void 函数的方法可能是完全错误的,因此任何关于如何测试不返回任何内容的函数的建议也会很棒。

【问题讨论】:

    标签: c++ unit-testing googletest googlemock


    【解决方案1】:

    你的例子离工作不远了。您可能会发现阅读gMock for Dummies 文档很有帮助。它很好地概述了基础知识。

    本质上,模拟允许您对它们设定期望,并验证是否满足了期望。您还可以执行诸如控制模拟方法的返回值之类的操作。模拟方法必须是虚拟的,但不要求它们是抽象的。

    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 使用的是具体(真实)类FooChild。您将需要一种方法将具体类替换为模拟类(使用某种形式的依赖注入)。这是一个简单的例子:

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

    【讨论】:

    • 谢谢!依赖注入正是我需要的关键字。我对编程比较陌生,所以这是非常有用的建议!
    • 如果有人正在寻找 Gmock for dummies 文档,it has moved
    【解决方案2】:

    除非你没有把它们放在这里,否则你会错过很多东西。慢慢阅读googletests 的文档,特别是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之后写方法的参数数量,然后是返回类型,括号之间是参数的类型。如果您不想担心这个,请使用库中的this nice generator

    然后在测试本身中定义模拟的行为,这就是它的重点,您可以对所有测试进行一般定义,或者将其更改为以不同的方式工作。

    我认为写一个完整的例子没有意义,因为你有in the tutorials really good and simple ones,所以检查一下。

    【讨论】:

    • 是的,你是对的,这样定义模拟方法可能更好,但这并不重要,因为我不确定这是否是正确的方法。我的问题是:我有一个方法,这个方法调用另一个类的函数,它不是虚拟的。现在我该如何测试这个。文档中的教程只是为抽象类展示了它。这就是为什么我用父类 Foo 尝试这种方法。
    • MOCK_METHOD 不带参数计数是最新 gMock 版本中的首选方法。 MOCK_METHOD&lt;N&gt;old style
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    相关资源
    最近更新 更多