覆盖非虚函数以进行测试

时间:2014-05-30 14:31:13

标签: c++ tdd override virtual cppunit

我有一个我需要模拟的类,但该类具有需要模拟的非虚方法。我的问题的简单版本如下所示:

#include <iostream>
#include <string>

using namespace std;

class Base{
   public:
    void getNext(){
        cout<<"Base Func"<<endl;
    }
};

class Derived: public Base{
   public:
    void getNext(){
        cout<<"Derived func"<<endl;
    }
};

int main(){
   Base *ptr = new Derived();
   ptr->getNext();
}

上面的代码将调用Base类的“getNext”函数,但我希望它以某种方式调用派生类。真正的问题是我创建了一个新类,其唯一的公共方法执行某些逻辑,并且还需要来自数据库的序列。从数据库中获取序列的类(称为DlSequence)是我们应用程序的基本代码(您可能调用的核心或产品),我无法更改它。现在我需要使用cppunit来测试我的课程。所以,我必须模拟或伪造DlSequence类并覆盖getNext函数,但此函数不是虚函数。是否有可能嘲笑它?或者我可以通过任何解决方法绕过此问题。 我没有使用任何模拟框架,但我在我的盒子中安装了mockpp,我无法安装任何其他模拟框架。提前谢谢。

3 个答案:

答案 0 :(得分:3)

答案简短:

如果该类的作者没有提供自定义行为的方法,那么这是不可能的。

如果您无法自行更改,请向他们提出您需要挂钩的问题。


答案很长:

就C ++而言,有可能尝试和破解它,但它既不安全又脆弱。在我的脑海中,我可以想到基于预处理器hackery在基类中注入virtual关键字,甚至使用LD_PRELOAD来覆盖函数符号......但老实说,两者都没有吸引力。

注意:如果我们正在讨论测试您的代码,并且您可以更改代码,那么您当然可以围绕此Base事件创建一个包装器,并将其设为virtual / { {1}} /不管;我想在这里你不能。

然而,就SQL而言,您可能有机会,例如将API调用甚至网络调用重定向到您控制下的模拟或数据库实例。不知道你的系统的细节,但我不能进一步建议。

答案 1 :(得分:0)

当您测试驱动需要与外部资源(例如,第三方库,I / O等)交互的代码时,您通常introduce a seam可以模拟出来依赖性。

这也适用于您的情况。如果您无法修改协作者的代码,那么它与第三方库(在这个意义上)没有太大区别。而不是试图直接模仿协作者,而是在代码和有问题的代码之间找出一条缝隙。

例如:

    #include <iostream>
    #include <string>

    using namespace std;

    class Base{
    public:
        void getNext(){
            cout << "Base Func" << endl;
        }
    };

    class Seam{
    public:
        virtual ~Seam() { }

        virtual void getNext() = 0;
    };

    class MockCollaborator : public Seam{
    public:
        void getNext(){
            cout << "Derived func" << endl;
        }
    };

    class RealCollaborator : public Seam{
    public:
        void getNext(){
            Base base;
            base.getNext();
        }
    };

    int main(){
        Seam* ptr = new MockCollaborator();
        ptr->getNext();
    }

答案 2 :(得分:0)

如果您可以制作课程模板,可以使用以下内容:

class Base {
public:
    void getNext() { cout << "Base Func" << endl; }
};

// Has the same interface of Base
class MockedBase {
public:
    void getNext() { cout << "Derived func" << endl; }
};

在你的课堂上,做一些像:

template <typename T> class myClass
{
public:
    void callGetNext() { base.getNext(); }
private:
    T base;
};

因此在实际代码中使用myClass<Base>,在unittest中使用myClass<MockedBase>

相关问题