c++ - pImpl 习语和可测试性

标签 c++ testing pimpl-idiom

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/

相关文章:

c++ - 使用模板化类的 pimpl 习语有什么优势吗?

c++ - 使用指针隐藏实现(Pimpl 惯用语)

c++ - 超轻型 gzip 压缩实现?

c++ - 通过类内类提升进程间共享内存

ruby-on-rails - 在 Rails 3 中测试非功能性需求的最佳实践

jenkins - 运行 testcafe 和 browserstack 时获取 "Unable to establish one or more of the specified browser connections"

c++ - Pimpl 习语和交换

c++ - std::max_element 编译错误,C++

c++ - 在 main 之前立即调用一个函数

ruby-on-rails - 测试期间 nil 类的未定义方法 '[]'