问题
I need to write the gtest to test some existing code that has a non-virtual method, hence I am testing using the below source, but I am getting the compilation error
package/web/webscr/sample_template_class3.cpp: In function âint main()â: package/web/webscr/sample_template_class3.cpp:64: error: âclass Templatemyclassâ has no member named âgmock_displayâ
sample_template_class3.cpp
#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace std;
template < class myclass>
class Templatemyclass
{
private:
myclass T;
public :
void display()
{
T.display();
}
};
class Test
{
public:
void display()
{
cout<<"Inside the display Test:" <<endl;
}
};
class MockTest
{
public:
MOCK_METHOD0(display,void());
};
class FinalTest
{
public:
void show( Templatemyclass<Test> t)
{
t.display();
cout<<"Inside the display FinalTest:" <<endl;
}
};
int main()
{
FinalTest test1;
Templatemyclass<Test> obj1;
Templatemyclass<MockTest> obj2;
EXPECT_CALL(obj2,display()).Times(1);
test1.show(obj1);
return 1;
}
回答1:
There are a couple of issues in your code. I have changed it below and commented the code by way of explanation. If this is not clear enough, add a comment and I'll try and explain further.
#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace std;
template <class myclass>
class Templatemyclass {
private:
// Hold a non-const ref or pointer to 'myclass' so that the actual
// object passed in the c'tor is used in 'display()'. If a copy is
// used instead, the mock expectations will not be met.
myclass* T;
public :
// Pass 'myclass' in the c'tor by non-const ref or pointer.
explicit Templatemyclass(myclass* t) : T(t) {}
void display() { T->display(); }
};
class Test {
public:
void display() { cout << "Inside the display Test:" << endl; }
};
class MockTest {
public:
MOCK_METHOD0(display, void());
};
class FinalTest {
public:
// Templatise this function so we can pass either a Templatemyclass<Test>
// or a Templatemyclass<MockTest>. Pass using non-const ref or pointer
// again so that the actual instance with the mock expectations set on it
// will be used, and not a copy of that object.
template<class T>
void show(T& t) {
t.display();
cout<<"Inside the display FinalTest:" <<endl;
}
};
int main() {
Test test;
Templatemyclass<Test> obj1(&test);
MockTest mock_test;
Templatemyclass<MockTest> obj2(&mock_test);
EXPECT_CALL(mock_test,display()).Times(1);
FinalTest test1;
test1.show(obj1);
test1.show(obj2);
return 0;
}
The following could possibly simplify the case:
#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
template <class myclass>
class Templatemyclass {
public:
myclass T;
void show() const { T.display(); }
};
struct Test {
void display() const { std::cout << "Inside the display Test:\n"; }
};
struct MockTest {
MOCK_CONST_METHOD0(display, void());
};
int main() {
Templatemyclass<Test> obj1;
obj1.show();
Templatemyclass<MockTest> obj2;
EXPECT_CALL(obj2.T, display()).Times(1);
obj2.show();
return 0;
}
回答2:
If you don't want to change your source code, you can leverage injector++. Currently it only supports x86 Windows. But Linux and x64 Windows support will come soon. Below examples will give you a brief idea:
Mock non-virtual methods
Below example fakes BaseClassTest::getAnInteger()
by using fakeFunc()
:
class FakeClassNonVirtualMethodTestFixture : public ::testing::Test
{
public:
int fakeFunc()
{
return 6;
}
};
TEST_F(FakeClassNonVirtualMethodTestFixture, FakeIntFunctionWhenCalled)
{
// Prepare
int expected = 6;
InjectorPP::Injector injector;
injector.whenCalled(INJECTORPP_MEMBER_FUNCTION(BaseClassTest::getAnInteger))
.willExecute(INJECTORPP_MEMBER_FUNCTION(FakeClassNonVirtualMethodTestFixture::fakeFunc));
BaseClassTest b = BaseClassTest();
// Act
// FakeFunc will be executed!
int actual = b.getAnInteger();
// Assert
EXPECT_EQ(expected, actual);
}
Mock virtual methods
Injector++ supports virtual method mocking (Amazing, huh?). Below is a simple example:
int FakeIntFuncForDerived()
{
return 2;
}
TEST_F(FakeClassVirtualMethodTestFixture, MockDerivedClassVirtualMemberFunctionWhenCalled)
{
// Prepare
int expected = 2;
BaseClassTest* derived = new SubClassTest();
InjectorPP::Injector injector;
injector.whenCalledVirtualMethod(derived, "getAnIntegerVirtual")
.willExecute(fakeIntFuncForDerived);
// Act
// FakeIntFuncForDerived() will be exectued!
int actual = derived->getAnIntegerVirtual();
// Assert
EXPECT_EQ(expected, actual);
delete derived;
derived = NULL;
}
Mock static methods
Injector++ supports static method mocking. Below is a simple example:
Address FakeGetAnAddress()
{
Address addr;
addr.setAddressLine("fakeAddressLine");
addr.setZipCode("fakeZipCode");
return addr;
}
TEST_F(FakeClassNonVirtualMethodTestFixture, FakeStaticFunctionReturnUserDefinedClassWhenCalled)
{
// Prepare
Address expected;
expected.setAddressLine("fakeAddressLine");
expected.setZipCode("fakeZipCode");
InjectorPP::Injector injector;
injector.whenCalled(INJECTORPP_STATIC_MEMBER_FUNCTION(BaseClassTest::getAnAddressStatic))
.willExecute(INJECTORPP_MEMBER_FUNCTION(FakeClassNonVirtualMethodTestFixture::fakeGetAnAddress));
// Act
// FakeGetAnAddress will be executed!
Address actual = BaseClassTest::getAnAddressStatic();
// Assert
EXPECT_EQ(expected, actual);
}
来源:https://stackoverflow.com/questions/15782887/mock-non-virtual-method-giving-compilation-error