可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
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); }