使C++代码易于测试的模式

11

你是否应该设计你的代码以使测试更容易?如果是这样,如何设计 c++ 代码以便于测试。

  • 如何在 c++ 中使用依赖注入?
  • 我是否应该使用纯接口类作为基类来实现类,以简化创建假测试对象的过程?
    • 这会迫使我编写很多虚拟方法。这会影响性能吗?
  • 在为 c++ 设计可测试性时,还应考虑什么?

设计可测试性确实是必须的。但是您还必须意识到,只有“边界”应该以独立方式进行测试,对于内部组件相互依赖且不在隔离状态下进行测试是完全合理的。 - Matthieu M.
你可能会对这个Stack Exchange提案感兴趣。它即将开始beta测试,只需要再招募一些人。 - greatwolf
4个回答

9
我应该使用纯接口类作为基类来实现类以简化创建虚拟测试对象吗?
这将迫使我创建许多虚拟方法。这会影响性能吗?
我经常使用的解决方法是将类模板化而不是将其隐藏在接口后面。然后,当进行测试时,我可以将测试/模拟对象作为模板参数传递,并在其他情况下使用真实对象。这样可以避免虚函数对性能的影响。
编辑:
好的,一个简单的例子:
使用面向对象技术和接口,你可能会写出这样一个函数:
void Foo(IBar& someBar) { ... }

这个函数接受一个实现了IBar接口的参数,并对其进行操作。如果你想传入一个虚拟的模拟实现,只需编写一个继承自IBar的模拟对象并将其传递给Foo即可。简单明了。

但是你也可以使用模板来实现相同的功能:

template <typename BarType>
void Foo(BarType& someBar) { ... }

...就是这样。 Foo的主体可以基本保持不变。只要传递给函数的类型公开了我们需要的所有成员,它就可以正常工作,而无需正式从接口类继承,并且没有虚函数和运行时多态性的开销。


在哪里可以读到更多有关类模板化的内容?是否有描述这个模式的文档? - Joakim Karlsson
为什么你想要所有东西都有一个模式?jalf向你展示了一个想法,即放弃继承(虚拟/多态),而是使用C++模板(泛型编程)。提供通用的模拟(模板代码)将覆盖您可能使用的“所有”可能类型(使用一个函数,而不是许多“虚拟方法”)。 - bua
3
当然,模板可能会使编译时依赖变得更加困难,因为它们的实现在头文件中。 - Matthieu M.
不,我并不是说我需要一个模式。我只是想看看他的意思举个例子。从他的回答中的文字,我还不明白jalf的意思。 - Joakim Karlsson
2
@Matthieu M:实现可能不必放在头文件中。请记住,实际的生产代码只会使用一组类型(真实的、非模拟的、非测试的)。因此,定义可能只需要在一个翻译单元中可见。然后你的测试可能直接包含.cpp文件。由于这个原因,你的测试代码可能会有点hackish,但这可能是一个值得的权衡——单元测试不必是超级优雅的代码。 - jalf

5
不要一开始就设计太多,先写一个测试,然后让它通过,但不要超过这个范围。让你的函数非常短小。看看你做了什么并进行重构。如果你要写注释,最好将相关代码放到一个具有良好名称的单独函数中。
不要花太多时间思考模式,那是很多科学和少量结果,只需先编写一个测试并保持代码简单,然后出奇地不需要为其编写测试,因为你已经完成了。你的代码可以工作。

1
如果你要写注释,最好将相关代码放到一个具有良好命名的单独函数中。这是非常好的建议。 - Steven Keith

3

0

我认为首要关注的应该是...

  1. 实现功能
  2. 代码可扩展性
  3. 代码可重用性
  4. 代码可维护性

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接