我认为你必须使用链接器接缝来做你想做的事。
假设我们有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.cpp和libraryToBeMockedImpl.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)),您将能够同时提供模拟库和接缝,但稍后应在库之前向链接器提供一个。