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

时间:2014-12-30 16:35:31

标签: c++ unit-testing inheritance virtual-method

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

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

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

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

为了使情况更加困难,类A, BC也包含公共属性,虚函数以及一些模板函数。

所以我的问题是:如何应对我上面描述的情况?有没有我错过的C ++功能,哪些可以帮助我的场景?任何设计模式?甚至是任何重构工具?我的主要要求是变化必须尽可能安全,因为我想要伪造的类对系统来说非常重要......我也会对一个“丑陋”的解决方案感到满意,这个解决方案可以让我进行测试到位(如果系统适当地覆盖了测试,可以在以后重构)。

编辑:我搞砸了我的继承层次结构(它是颠倒的) - 现在已经纠正了。

Edit2:我们最终结果如下:我们只制作了我们当前测试用例实际需要的虚拟函数。然后我们检查了对这些方法的每次调用(这是可管理的)。这使我们可以使用Google Mocks模拟我们的课程。有越来越多的测试用例,希望我们的变化能够随着时间的推移而变得更加节省。请注意,在提出我的问题时,我认为Google Mocks只能模拟纯接口;这是 not 的情况,因此允许如上所述的增量方法。

2 个答案:

答案 0 :(得分:2)

我建议将C更改为模板,其中模板类型是实际的数据库访问/实现代码。然后,在您的实时计划中,您使用C<LiveDatabase>当前使用C的任何位置,并在测试时使用C<MockDatabase>。然后AB保持不变,C内部工作的所有部分保持不变,只有特定的数据库调用不同(在他们对委托实现的调用中)。 / p>

接下来我会继续研究公共属性,因为它们只会让你头痛并且难以发现错误。只需简单地将它们全部设为私有,让你的编译器告诉你他们是否被访问了。对于只读使用,只需添加访问器就非常容易。在他们被突变的地方,您需要确定适合您的类的接口以实现所需的突变。不要只添加一个mutator方法,除非这绝对是你的最后一个选择。

答案 1 :(得分:1)

编辑:根据DietmarKühl的评论,这种方法无法伪造成员函数模板。

我不确定这是否可行,但尝试在单独的.cpp文件中创建一个假类(非虚拟)。然后,将测试与假类连接,但不是真实类。从理论上讲,这两个具有相同的ABI(应用二进制接口),因此两者应该是兼容的。