c++ - 如何伪造包含非虚函数的 C++ 类?

标签 c++ unit-testing inheritance virtual-functions

我正在尝试对一些 C++ 遗留代码进行测试。特别是,我有一个类层次结构,比如说 A < B < C (即 AB 的子类,BC 的子类),并且存在对 C 类型对象的全局引用它用于整个系统的代码(单例模式)。目标是取代那个 C带有一些假对象的对象(实际上,C 用于访问数据库)。

我的第一次尝试是引入接口(interface) IA, IB, and IC (其中包含相应类的函数的纯虚版本),让每个类实现其接口(interface),并更改全局类型 C引用IC .在测试的设置函数中,我将替换全局引用的 C对象与我自己的实现 IC ,让整个系统使用我的假实现。

但是,类 A, B , 和 C每个都包含相当多的非虚函数。现在,如果我要让这些类继承 self 的接口(interface),我会将这些函数的语义从非虚拟更改为虚拟(Feathers 在“有效地使用遗留代码”,第 367 页中讨论了这个问题)。换句话说:我必须检查对我的全局对象的每一次调用,并且我必须确保在我的更改之后,仍然调用相同的函数。这听起来像是很多容易出错的工作。

我还考虑过将非虚函数设为“final”,即告诉编译器 A, B 的函数和 C不能隐藏在子类中(这会让编译器告诉我所有 BC 的潜在危险函数——如果一个函数没有隐藏在基类中,上述效果根本不会发生),但是C++ 似乎不支持(我们还没有使用 C++11,但即使它的 final 关键字似乎也只适用于虚函数)。

为了让情况变得更加困难,类 A, B , 和 C还包含公共(public)属性、虚函数以及一些模板函数。

所以我的问题是:如何应对我上面描述的情况?是否有任何我错过的 C++ 功能,哪些可以帮助我的场景?有什么设计模式吗?甚至任何重构工具?我的主要要求是更改必须尽可能安全,因为我想伪造的类对系统来说相当重要......我也很高兴有一个“丑陋”的解决方案,它允许我进行测试到位(如果系统适本地覆盖了测试,以后可以重构)。

编辑:我弄乱了我的继承层次结构(它是颠倒的)- 现在已更正。

Edit2:我们最终的结果如下:我们只将我们当前测试用例实际需要的功能设为虚拟。然后我们检查了对这些方法的每次调用(这是可管理的)。这让我们可以使用 Google Mocks 模拟我们的类(class)。有了越来越多的测试用例,希望我们的更改能够随着时间的推移而节省下来。请注意,在问我的问题时,我认为 Google Mocks 只能模拟纯接口(interface); 不是这种情况,因此允许采用如上所述的增量方法。

最佳答案

我建议更改 C到模板中,其中模板类型是实际的数据库访问/实现代码。然后在您的实时程序中使用 C<LiveDatabase>你目前使用的任何地方C测试时使用 C<MockDatabase> .那么AB保持不变,所有C的碎片的内部工作原理保持不变,只有特定的数据库调用有所不同(在对委托(delegate)实现的调用中)。

接下来我将深入研究公共(public)属性,因为它们只会让您头疼和难以发现错误。只需将它们全部设为私有(private),让您的编译器告诉您它们是否正在被访问。对于只读使用,只需添加访问器就非常容易。在它们发生变异的地方,您需要确定您的类的适当接口(interface)以实现所需的变异。除非那绝对是您最后的选择,否则不要只添加一个增变器方法。

关于c++ - 如何伪造包含非虚函数的 C++ 类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27709090/

相关文章:

c++ - C++ 线程之间的内存共享

c++ - C++ 中的引用到引用是什么意思? (不是右值引用)

c++ - catch(...) 吞下 xcode llvm 3.0 中的所有其他捕获

.net - 自定义 WCF 扩展的单元测试,例如自定义行为和检查器

java - java中的动态方法绑定(bind) - 为什么这个方法?

c++ - sprintf 引起的 exc_bad_access

c++ - 使用自定义比较器传递 map 以发挥作用

c# - 使用 nMoq,人们对给定的事件有何期望?

java - 为什么变量在覆盖时的行为与方法不同。?

c++ - 子类对象作为虚函数的参数