Mock non-virtual method giving compilation error

前端 未结 2 992
清歌不尽
清歌不尽 2021-01-14 21:16

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

相关标签:
2条回答
  • 2021-01-14 21:27

    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);
    }
    
    0 讨论(0)
  • 2021-01-14 21:41

    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;
    }
    
    0 讨论(0)
提交回复
热议问题