C++ 没有虚拟方法的模拟类

C++ 没有虚拟方法的模拟类,c++,googletest,googlemock,C++,Googletest,Googlemock,我刚刚开始使用GoogleMock对生产代码进行单元测试。我想要模拟的类中没有虚拟方法。通过阅读GoogleMock上的一些内容,难道不可能模拟这样一个类吗?请记住,我不想对源代码进行任何更改 class Test { Test(void); virtual ~Test() {} Add(); }; int Test::Add() { return 1; } class MockTest : public Test { public: MOCK_MET

我刚刚开始使用GoogleMock对生产代码进行单元测试。我想要模拟的类中没有虚拟方法。通过阅读GoogleMock上的一些内容,难道不可能模拟这样一个类吗?请记住,我不想对源代码进行任何更改

class Test
{
    Test(void);
    virtual ~Test() {}
    Add();
};

int Test::Add()
{
    return 1;
}

class MockTest : public Test
{
public:
    MOCK_METHOD0(Add,int(void));
};

可能有一种方法,但它不如重写虚函数的简单方法好

首先,如果函数不是虚拟的,并且是内联的,那么很可能是运气不好。当编译器看到对
obj.Add()
ptr->Add()
的调用时,函数不是虚拟的这一事实意味着它不需要担心除了
Test::Add()
之外的一些函数可能需要实际调用。因此,它很可能直接内联
Add
定义中的代码,在这种情况下几乎不可能替换它,或者将
Test::Add()
的弱链接副本放入调用它的函数所在的同一个对象文件中。在第二种情况下,您可能可以使用链接器技巧替换它,这取决于您使用的平台—直到稍后编译器切换到决定将其内联

如果您不想修改的只是类
Test
,但是您可以更改将
Test
用作依赖项并将由单元测试测试的代码,那么您可以执行模板依赖项注入。但是这个问题听起来好像你也不想修改代码

现在假设函数不是内联函数,并且在某个文件“Test.cpp”中定义,并且该类是多态的(在本例中是多态的,因为存在虚拟析构函数),则可以替换该文件中的所有定义,以使它们看起来像是虚拟的,即使它们不是:

  • 像往常一样编写GoogleMock类,其中包含您希望能够检测Mock的函数

    #include "Test.hpp"
    #include <gmock/gmock.h>
    
    class MockTest : public Test
    {
    public:
        MOCK_METHOD0(Add, int());
        MOCK_CONST_METHOD0(Print, void());
    };
    
    #包括“Test.hpp”
    #包括
    类MockTest:公共测试
    {
    公众:
    模拟方法0(添加,int());
    模拟常量方法0(打印,void());
    };
    
  • (我在示例中添加了一个const方法,以演示如何处理它们。)

  • 在相同的单元测试代码中,为模拟函数编写如下定义

    int Test::Add()
    {
        if (auto* mock = dynamic_cast<MockTest*>(this))
            return mock->Add();
        // Next comes what to do if the code ever calls Add on
        // a Test which is not actually a MockTest. This could
        // be a stub implementation, an actual implementation, or
        // could intentionally terminate, throw, or note a gtest error.
        ADD_FAILURE() << "Test is not a MockTest";
        return 0;
    }
    
    void Test::Print() const
    {
        if (auto* mock = dynamic_cast<const MockTest*>(this)) {
            mock->Print();
            return;
        }
        ADD_FAILURE() << "Test is not a MockTest";
    }
    
    int测试::添加()
    {
    如果(自动*mock=dynamic_cast(此))
    返回mock->Add();
    //接下来,如果代码调用了Add-on,该怎么办
    //实际上不是模拟测试的测试。这可能
    //是存根实现、实际实现或
    //可以故意终止、抛出或记录gtest错误。
    添加_FAILURE()打印();
    返回;
    }
    添加_失败()