在不编辑生产代码的情况下用C ++模拟非虚方法?

时间:2010-02-26 04:46:17

标签: c++ unit-testing mocking googlemock

我是一个相当新的软件开发人员,目前正在为几年前开始的现有C ++项目添加单元测试。由于非技术原因,我不允许修改任何现有代码。我所有模块的基类都有一堆设置/获取数据和与其他模块通信的方法。

由于我只想对每个单独的模块进行单元测试,因此我希望能够为所有模块间通信方法使用预设值。即对于Ping()方法,它检查另一个模块是否处于活动状态,我希望根据我正在进行的测试类型返回true或false。我一直在研究Google Test和Google Mock,它确实支持模拟非虚拟方法。然而,所描述的方法(http://code.google.com/p/googlemock/wiki/CookBook#Mocking_Nonvirtual_Methods)要求我“模板化”原始方法以接受真实或模拟对象。由于前面提到的要求,我无法去基类中模拟我的方法,所以我需要一些其他方法来模拟这些虚方法

基本上,我想要模拟的方法是在一些基类中,我想要单元测试的模块和创建模拟的模块是该基类的派生类。我的基本Module类和我想测试的模块之间有中间模块。

我很感激任何建议!

谢谢,

JW

编辑:一个更具体的例子

我的基类是rootModule,我要测试的模块是leafModule。有一个继承自rootModule的中间模块,leafModule继承自这个中间模块。

在我的leafModule中,我想测试doStuff()方法,该方法调用rootModule类中定义的非虚拟GetStatus(moduleName)。我需要以某种方式使GetStatus()返回一个选定的固定值。模拟对我来说是新的,所以使用模拟对象甚至是正确的方法吗?

3 个答案:

答案 0 :(得分:13)

有一些不同的方法可以替换非虚函数。一种方法是重新声明它们,并为您要测试的每组不同的非虚函数编译一个新的测试可执行文件。那几乎不可扩展。

第二种选择是使它们虚拟化以进行测试。大多数编译器允许您在命令行上定义一些内容,因此使用-DTEST_VIRTUAL = virtual或-DTEST_VIRTUAL编译代码,使其成为虚拟或正常,具体取决于它是否在测试中。

可以使用的第三个选项是使用模拟框架来模拟非虚函数。我是HippoMocks的作者(关于中立性的免责声明等),我们最近添加了在X86平台上模拟普通C函数的功能。这可以通过一些工作扩展到非虚拟成员函数,并且将是您正在寻找的。请记住,如果您的编译器一次可以看到函数的使用和定义,它可能会内联它并且模拟可能会失败。这尤其适用于标题中定义的函数。

如果常规C函数模拟对您来说已经足够,您可以像现在一样使用它。

答案 1 :(得分:3)

我会写一个Perl / Ruby / Python脚本来读取原始源代码树,并在不同的目录中写出一个模拟的源代码树。您不必完全解析C ++以替换函数定义。

答案 2 :(得分:1)

一种方法是指定不同的测试来源。假设您的生产目标使用rootModule.h和rootModule.cpp。为测试目标使用不同的来源。您可以通过更改包含路径来指定不同的标头,以便#include“rootModule.h”实际加载unittest / rootModule.h。然后根据你的内心模拟rootModule。