I am using VS2005 and gmock ver. 1.6 for unit testing.
I have the following code which I want to mock, but I cannot find a way to do so.
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();
}
Where getInstance(int x)
is just creating an instance of B and returns it. Whereas getInstance()
just returns the already created instance by getInstance(int x)
;
I have the mock class,
class MockA : public A
{
MOCK_METHOD0(foo1, bool());
MOCK_METHOD0(foo2, bool());
}
In the sources, I am using
bool retVal = B::getInstance()->foo2()
How can I mock this behavior B::getInstance()
?
I think that you have to use linker seam to do what you want.
Let's say that we have libraryToBeMocked
with the interface placed in 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;
};
You should have noticed that I have altered your design. Both getInstance
method returns pointer to Base
not Derived
. If you want to mock the logic clearly you should mock the pure interface Derived already has some logic in it. IMHO both getInstance
methods should be moved to other class anyways.
The implementation of the library is in 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) {}
There is also the logic which you want to test. testedLibrary.hpp
:
#pragma once
bool isOdd(int x);
bool isEven(int x);
implementation 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();
}
Dummy main
in main.cpp
:
#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;
}
I don't use VS, but I think all it takes is to add main.cpp
testedLibraryImpl.cpp
and libraryToBeMockedImpl.cpp
to the project. I would rather use gcc:
g++ main.cpp libraryToBeMockedImpl.cpp testedLibraryImpl.cpp -o production
Well, let's start with my answer. I would create header file 'libraryMockSeam.hpp':
#pragma once
#include "libraryToBeMocked.hpp"
class Provider
{
public:
virtual Base* getInstance() = 0;
virtual Base* getInstance(int x) = 0;
};
Provider* registerNewMockProvider(Provider*);
and 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);
}
As you can see this source file provides it's own implementation of getInstance
methods. It delegates it to the registered Provider. The headers introduced the Provider interface and a function that allows to register your provider. That's it.
Let's look at the test:
#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));
}
I would compile it like that:
g++ test.cpp testedLibraryImpl.cpp libraryMockSeam.cpp -lgmock -lgmock_main -lpthread -o test
You should notice that I did not provide libraryToBeMocked.cpp
in this case, the implementation is already provided by libraryMockSeam.cpp
. In case you would like to use whole libraries (that is *.lib
files(or *.a
)) You would be able to provide both mocked library and the seam but later one should be provided to the linker before the library.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.