c++ 中的 pImpl 习惯用法旨在向该类的用户隐藏该类的实现细节(=私有(private)成员)。 然而,它也隐藏了该类的一些依赖关系,从测试的角度来看,这些依赖关系通常被认为是不好的。
例如,如果 A 类将其实现细节隐藏在只能从 A.cpp 访问的 AImpl 类中,并且 AImpl 依赖于许多其他类,那么对 A 类进行单元测试就变得非常困难,因为测试框架无法访问AImpl的方法,也没有办法将依赖注入(inject)到AImpl中。
以前有人遇到过这个问题吗?你找到解决办法了吗?
-- 编辑--
在一个相关主题上,似乎人们建议只测试接口(interface)公开的公共(public)方法,而不是内部方法。虽然我可以从概念上理解该陈述,但我经常发现我需要单独测试私有(private)方法。例如,当公共(public)方法调用包含一些非平凡逻辑的私有(private)帮助方法时。
最佳答案
pimpl 背后的想法不是对类隐藏实现细节(私有(private)成员已经这样做了),而是将实现细节移出标题。问题在于,在 C++ 的包含模型中,更改私有(private)方法/变量将强制重新编译包括该文件在内的任何文件。这是一种痛苦,这就是为什么 pimpl 试图消除。它无助于防止对外部库的依赖。其他技术可以做到这一点。
您的单元测试不应依赖于类的实现。他们应该验证您的类(class)是否确实按照应有的方式行事。唯一真正重要的是对象如何与外部世界交互。您的测试无法检测到的任何行为都必须是对象内部的,因此是不相关的。
话虽如此,如果您发现类的内部实现过于复杂,您可能希望将该逻辑分解为单独的对象或函数。本质上,如果您的内部行为过于复杂而无法间接测试,请将其作为另一个对象的外部行为并进行测试。
例如,假设我有一个类,它接受一个字符串作为其构造函数的参数。字符串实际上是一种小型语言,用于指定对象的某些行为。 (字符串可能来自配置文件或其他东西)。理论上,我应该能够通过构造不同的对象并检查行为来测试该字符串的解析。但是,如果迷你语言足够复杂,这将很难。所以,我定义了另一个函数,它接受字符串并返回上下文的表示(如关联数组或其他东西)。然后我可以将解析函数与主对象分开测试。
关于c++ - pImpl 习语和可测试性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2785206/