C++中的可测试性设计
本文关键字:可测试性设计 C++ | 更新日期: 2023-09-27 18:27:29
我想了解在C++中设计可测试应用程序的最佳方法,也许与C#相比(因为它是我的背景,非常适合测试)
我习惯于对接口、依赖项注入、控制框架的反转和mock对象进行编码。由于C#有很多不同的语言特性,我不确定有多少模式应该仍然适用。我还认为C++的独特特性/局限性可能适用于不同的测试策略。
我看过单元测试框架,我喜欢谷歌测试,但写尽可能可测试的新代码也很重要。
- 有没有什么开源项目可以推荐为C++测试做得对吗
- 有没有更详细地介绍这个主题的书或文章
- 关于其他框架/库的建议
感谢
我现在也处于完全相同的情况。来自C#背景,现在我正在编写新的(并扩展遗留的)C++应用程序。
我想,共同的背景给我们留下了共同的问题。我很惊讶在遗留应用程序中,依赖项与类的耦合如此紧密。
正如您所强调的,令人担忧的是,C#中的最佳实践可能不是C++中的最佳方式。经过大量的研究,我自己的一些Stack Overflow问题,以及一些原型设计,我最终得到了一个C++体系结构,它在很多方面反映了我觉得在C#中最有效的东西。
以下是我使用的主要原则:
-
依赖注入
类的构造函数将依赖项的接口作为参数进行模拟。在某些情况下,这意味着为依赖项编写包装器,例如boost::filesystem,它主要在模板化的头文件中实现。在我看来,值得付出一点小小的努力,因为它将我们与可能更改或被我们交换的库松散地耦合在一起,并且它允许我们使用mock实现进行单元测试。
-
边测试边测试!
这应该是不言而喻的,但是在编写类的同时编写测试允许您在可测试性方面对设计进行健全性检查。我不在乎你先测试,做TDD,或者不管你怎么称呼它,我的理念就是在你开始使用代码库中的类之前编写测试。
-
谷歌测试作为我们的单元测试框架
到目前为止,我已经使用了Cxxtest(遗留应用程序)和谷歌测试。谷歌测试在执行时提供了许多灵活的选项,以确定您运行的测试集。我们将类命名约定划分为UnitTest_xxxx和IntegrationTest_xxxx。然后在命令行中,我可以告诉gtest只使用一个名称、另一个名称或同时使用这两个名称运行测试。然后,我的构建服务器可以在晚上对整个测试套件执行长时间运行的测试,但每次签入时都要执行单元测试。Cxxtest可以做同样的事情,但需要更多的工作,而且由于多种原因,它通常很笨重。
-
测试时模拟对象的谷歌模拟
依赖注入的明显好处是在测试过程中使用模拟对象。人们可以简单地编写每个接口的伪实现,但GoogleMock允许快速旋转伪对象,并提供了你所期望的Moq或RhinoMock等优秀.NET mocking框架的典型检查。
我使用了CPP单元,它是JUnit的一个端口。它非常易于使用,并以XML格式提供输出,这非常棒。至于如何使用它,你可以在这里查看食谱。
在某些情况下,我看到你提到的所有技术(接口编码、依赖项注入、控制框架反转和模拟对象)都被滥用,最终使事情变得更加困难。尽管这些技术可以得到很好的利用,但有时我看到它们被宣传,就好像它们是通往质量的唯一道路。我不同意。
在我看来,保证C++中代码质量的最重要的开发技术是使用面向对象技术,如模块性、开闭原则、自文档、命令查询分离等。
特别是,我认为重要的两种技术是DesignbyContract(请参阅问题C++中实现断言检查的最佳方式是什么?以及C++中的DesignbyContract?)和单元测试(请参阅相关问题1、2、3)。对于这两个问题,您都有合理的C++工具,如链接的问题所示。
我可以推荐UnitTest++和AMOP进行测试驱动的开发。两者的设置都非常简单,功能也非常强大。如果你不需要谷歌测试中的所有功能,这是一个不错的选择。
它们可能看起来已经过时了,因为它们已经有一段时间没有更新了,但我对它们没有任何问题。