【问题标题】:Mock non-virtual method giving compilation error模拟非虚拟方法给出编译错误
【发布时间】:2013-04-03 08:57:08
【问题描述】:

我需要编写 gtest 来测试一些具有非虚拟方法的现有代码,因此我正在使用以下源进行测试,但出现编译错误

package/web/webscr/sample_template_class3.cpp:在函数âint main()â中: package/web/webscr/sample_template_class3.cpp:64:错误:“class Templatemyclass”没有名为“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;
}

【问题讨论】:

    标签: c++ googletest googlemock


    【解决方案1】:

    您的代码中有几个问题。我在下面进行了更改,并通过解释对代码进行了注释。如果这还不够清楚,请添加评论,我会尝试进一步解释。

    #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;
    }
    

    以下可能会简化案例:

    #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;
    }
    

    【讨论】:

    • 弗雷泽的另一个很棒的回答!!!嘿,弗雷泽,我正在四处寻找有关如何在不使用模板的情况下模拟非虚拟方法的信息。我发现了一些非常有趣的答案,包括这两个:stackoverflow.com/a/2857770/1735836stackoverflow.com/q/1127918/1735836。很想听听你的想法!!!
    • 我想我会倾向于尝试 HippoMocks,但我没有个人经验。我们在代码库中使用了 GoogleMock 一段时间,设置和维护测试非常痛苦。例如,它与 C++11 智能指针真的不兼容。我听说过的另一种可能性是typemock.com/isolatorpp-product-page。这应该避免您也不得不更改生产代码来进行测试,但我认为它不是免费的,而且我也没有个人经验。除此之外,我会选择两个选项之一......
    • ...stackoverflow.com/a/2857770 中提到。我讨厌修改源代码只是为了适应测试,所以我会避免stackoverflow.com/q/1127918 问题中的选项。这样就剩下 1. 重新声明要测试的功能或 2. 如果设置了给定的 PP 标志,则注入“虚拟”。对我来说,决定取决于要测试的实际代码。我喜欢 1 因为它是非侵入性的,但如果有很多功能需要测试,这可能是不可能的。对于 2,我会确保只为那些真正需要它的测试设置 PP 标志 - 正常测试使用真正的功能。
    【解决方案2】:

    如果您不想更改源代码,可以利用injector++。 目前它只支持 x86 Windows。但 Linux 和 x64 Windows 支持很快就会到来。下面的例子会给你一个简单的想法:

    模拟非虚拟方法

    以下示例使用fakeFunc() 伪造BaseClassTest::getAnInteger()

    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);
    }
    

    模拟虚拟方法

    Injector++ 支持虚拟方法模拟(太棒了,嗯?)。下面是一个简单的例子:

    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;
    }
    

    模拟静态方法

    Injector++ 支持静态方法模拟。下面是一个简单的例子:

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-29
      • 2020-02-09
      • 1970-01-01
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      相关资源
      最近更新 更多