gmock - 模拟派生类的非虚拟方法

gmock - mocking non-virtual method of the derived class

本文关键字:虚拟 方法 模拟 派生 gmock      更新时间:2023-10-16

我正在使用VS2005和gmock ver. 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()模拟这种行为?

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

假设我们已经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.cpp testedLibraryImpl.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方法实现。它将其委托给注册的提供程序。标头引入了提供程序接口和允许注册提供程序的函数。就是这样。

让我们看一下测试:

#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.cpplibraryMockSeam.cpp 已经提供了实现。如果您想使用整个库(即*.lib文件(或*.a)),您将能够同时提供模拟库和接缝,但稍后应在库之前提供给链接器。