【问题标题】:gmock - mocking non-virtual method of the derived classgmock - 模拟派生类的非虚方法
【发布时间】:2015-03-12 10:34:46
【问题描述】:

我正在使用 VS2005 和 gmock 版本。 1.6 用于单元测试。

我有以下要模拟的代码,但我找不到这样做的方法。

class A
{
 virtual bool foo1() = 0;
 virtual bool foo2() = 0;
};

class B : public A
{
 virutal bool foo1();
 virtual bool foo2();
 static B* getInstance(int x);
 static B* getInstance();
}

getInstance(int x) 只是创建 B 的一个实例并返回它。而getInstance() 只是返回getInstance(int x) 已经创建的实例;

我有模拟课,

class MockA : public A
{
 MOCK_METHOD0(foo1, bool());
 MOCK_METHOD0(foo2, bool());
}

在来源中,我正在使用

bool retVal = B::getInstance()->foo2()

如何模拟这种行为B::getInstance()

【问题讨论】:

    标签: c++ unit-testing googlemock


    【解决方案1】:

    我认为你必须使用链接器接缝来做你想做的事。

    假设我们有libraryToBeMocked,接口放置在libraryToBeMocked.hpp

    #pragma once
    
    class Base
    {
    public:
        virtual bool evenCheck() = 0;
        virtual bool oddCheck() = 0;
    };
    
    class Derived : public Base
    {
    public:
        virtual bool evenCheck();
        virtual bool oddCheck();
        static Base* getInstance(int x);
        static Base* getInstance();
    
    private:
        Derived(int x);
    
        int x;
    };
    

    你应该注意到我改变了你的设计。 getInstance 方法都返回指向 Base 而不是 Derived 的指针。如果你想清楚地模拟逻辑,你应该模拟纯接口 Derived 已经有一些逻辑。恕我直言,无论如何getInstance 方法都应该移到其他类。

    库的实现在libraryToBeMockedImpl.cpp

    #include "libraryToBeMocked.hpp"
    
    #include <memory>
    #include <cstdlib>
    
    bool Derived::evenCheck() { return x % 2 == 0; }
    
    bool Derived::oddCheck() { return x % 2 != 0; }
    
    namespace
    {
        std::auto_ptr<Derived> current(NULL);
    }
    
    Base* Derived::getInstance(int x)
    {
        current.reset(new Derived(x));
    
        return current.get();
    }
    
    Base* Derived::getInstance()
    {
        return current.get();
    }
    
    Derived::Derived(int x) : x(x) {}
    

    还有你要测试的逻辑。 testedLibrary.hpp:

    #pragma once
    
    bool isOdd(int x);
    bool isEven(int x);
    

    实现testedLibraryImpl.cpp:

    #include "testedLibrary.hpp"
    
    #include "libraryToBeMocked.hpp"
    
    bool isOdd(int x)
    {
        return Derived::getInstance(x)->oddCheck();
    }
    
    bool isEven(int x)
    {
        return Derived::getInstance(x)->evenCheck();
    }
    

    main.cpp 中的虚拟 main

    #include <iostream>
    
    #include "testedLibrary.hpp"
    
    using namespace std;
    
    int main()
    {
        int x;
        cin >> x;
    
        cout << x << " is odd:" << boolalpha << isOdd(x) << endl;
        cout << x << " is even:" << boolalpha << isEven(x) << endl;
    
        return 0;
    }
    

    我不使用VS,但我认为只需将main.cpptestedLibraryImpl.cpplibraryToBeMockedImpl.cpp添加到项目中即可。我宁愿使用 gcc:

    g++ main.cpp libraryToBeMockedImpl.cpp testedLibraryImpl.cpp -o production
    

    好吧,让我们从我的答案开始。我会创建头文件'libraryMockSeam.hpp':

    #pragma once
    
    #include "libraryToBeMocked.hpp"
    
    class Provider
    {
    public:
        virtual Base* getInstance() = 0;
        virtual Base* getInstance(int x) = 0;
    };
    
    Provider* registerNewMockProvider(Provider*);
    

    libraryMockSeam.cpp:

    #include "libraryMockSeam.hpp"
    
    namespace
    {
    Provider* currentProvider = 0;
    }
    
    Provider* registerNewMockProvider(Provider* newProvider)
    {
        Provider* t = currentProvider;
        currentProvider = newProvider;
        return t;
    }
    
    Base* Derived::getInstance()
    {
        return currentProvider->getInstance();
    }
    
    Base* Derived::getInstance(int x)
    {
        return currentProvider->getInstance(x);
    }
    

    如您所见,此源文件提供了它自己的getInstance 方法实现。它将它委托给注册的提供者。标头介绍了 Provider 接口和允许注册您的提供程序的功能。就是这样。

    我们来看看测试:

    #include "testedLibrary.hpp"
    #include "libraryMockSeam.hpp"
    
    #include <gtest/gtest.h>
    #include <gmock/gmock.h>
    
    using namespace ::testing;
    
    class MockProvider : public Provider
    {
    public:
     MOCK_METHOD1(getInstance, Base*(int x));
     MOCK_METHOD0(getInstance, Base*());
    };
    
    class MyMock : public Base
    {
    public:
     MOCK_METHOD0(evenCheck, bool());
     MOCK_METHOD0(oddCheck, bool());
    };
    
    class MyTestSuite : public Test
    {
    public:
        MyTestSuite()
        {
            registerNewMockProvider(&provider);
        }
    
        StrictMock<MyMock> mock;
        StrictMock<MockProvider> provider;
    };
    
    TEST_F(MyTestSuite, checksForOddValue)
    {
        EXPECT_CALL(provider, getInstance(1)).Times(2).WillRepeatedly(Return(&mock));
    
        EXPECT_CALL(mock, evenCheck()).WillOnce(Return(false));
        EXPECT_CALL(mock, oddCheck()).WillOnce(Return(true));
    
        EXPECT_TRUE(isOdd(1));
        EXPECT_FALSE(isEven(1));
    }
    
    TEST_F(MyTestSuite, checksForEvenValue)
    {
        EXPECT_CALL(provider, getInstance(1)).Times(2).WillRepeatedly(Return(&mock));
    
        EXPECT_CALL(mock, evenCheck()).WillOnce(Return(true));
        EXPECT_CALL(mock, oddCheck()).WillOnce(Return(false));
    
        EXPECT_TRUE(isEven(1));
        EXPECT_FALSE(isOdd(1));
    }
    

    我会这样编译:

    g++ test.cpp testedLibraryImpl.cpp libraryMockSeam.cpp -lgmock -lgmock_main -lpthread -o test
    

    您应该注意到,在这种情况下我没有提供libraryToBeMocked.cpp,实现已经由libraryMockSeam.cpp 提供。如果您想使用整个库(即*.lib 文件(或*.a)),您将能够同时提供模拟库和接缝,但稍后应在库之前向链接器提供一个。

    【讨论】:

    • 很抱歉收到了回复。非常感谢。我会尝试你的解决方案。我有这个想法,比如创建一个接缝。但我在想是否还有其他解决方案。我将在这里更新它是如何工作的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多