替代“#ifdef”防范来抑制对特定类的调用

时间:2014-02-18 09:02:55

标签: c++ mocking refactoring

我正在重新考虑GUI和后端高度耦合的应用程序,主要是因为在整个地方调用特定的类MainGui来刷新屏幕或显示特定的消息,如< / p>

getMainGui()->refreshDisplay()
getMainGui()->beginUpdate()
getMainGui()->showMessage()

因此,有些模块在没有GUI的情况下是不可测试的。我们需要创建一个可用于测试的命令行可执行文件。

我想在命令行上调用no-op。最明显的方法是使用#ifdef来保护呼叫,但是有数百个引用...我希望尽可能地进行本地化更改。有什么想法吗?

ps:我可以修改MainGuigetMainGui()

4 个答案:

答案 0 :(得分:0)

为什么不为MainGui创建另一个实现?出于测试目的:

getMainGui()

将返回MainGuiMock,在getMainGui()中你可以使用ifdef来决定返回哪个实现。

[编辑]

根据getMainGui()现在的样子,您可以根据外部配置文件或命令行选项决定要返回的实现。但这需要MainGui和MainGuiMock的一些共同基类。

实际上这取决于您的要求,我的第一个建议是要求您拥有.exe文件,一个用于测试,另一个用于实际的GUI应用程序。在[edit]之后建议使用依赖注入,您将拥有可以配置为在命令提示符中执行测试用例的单一exe。

答案 1 :(得分:0)

最简单的解决方案是使用虚方法的辅助基类。这不像单个虚拟呼叫的成本会影响refreshDisplay性能。 TestGui实施当然是无操作

答案 2 :(得分:0)

这听起来像Null Object pattern

的完美动机

您需要创建GUI接口的两个实现:一个不执行任何操作(null对象),另一个实际显示和更新接口。

根据您是在命令行还是使用GUI运行应用程序,getMainGui()应返回相应的对象。然后,所有其他方法可以继续调用GUI函数,但在命令行上进行测试时,不会发生任何影响。

维基百科甚至在C ++中提供了一个示例实现:

class animal {
  public:
    virtual void make_sound() = 0;
};

class dog : public animal {
  void make_sound() { cout << "woof!" << endl; }
};

class null_animal : public animal {
  void make_sound() { }
};

答案 3 :(得分:0)

是的,根据其他答案,您可以创建定义这些GUI功能的虚拟基类,然后从中导出“真实”GUI版本和无操作版本。根据具体的实现 - 你可能不得不尽量避免来自调用的性能损失在你的实际构建中开始实际调度(对于简单的get / set函数,最多约为一个数量级,非常受编译器/编译器开关/ CPU /等)。如果您接受这样的性能损失,可能将不会注意到它,但您可能(或者更糟糕的是 - PC速度较慢的用户).... ....

还有很多其他选择,包括:

  • 如果应用程序代码本身属于模板化的类型(或模板化的合理类型),则可以提供GUI类类型以用作模板参数

  • 如果应用程序代码在其实现文件中使用静态/匿名命名空间主GUI全局,则可以#ifdef只用该行代替测试版

(如果您发布更多的实际代码,则更容易提出具体建议,因为很多时候取决于哪些标题,独立版和类成员等等。