如何对继承对象进行单元测试?
Posted
技术标签:
【中文标题】如何对继承对象进行单元测试?【英文标题】:How do I unit-test inheriting objects? 【发布时间】:2010-09-11 04:14:22 【问题描述】:当您使用组合时,您可以模拟其他对象 您的被测类所依赖的,但是当您使用 继承,你不能模拟基类。 (或者你可以吗?)
我一般尝试prefer composition over inheritance, 但有时继承似乎真的是最好的工具 对于这项工作 - 好吧,至少在涉及到单元测试之前。
那么,如何测试继承?或者你只是把它当作垃圾 不可测试并改用组合?
注意:我主要使用 php 和 PHPUnit,所以请帮忙 最受赞赏。但知道也会很有趣 如果有其他语言的解决方案。
【问题讨论】:
我不明白如何模拟超类。那必须是 ihmo 的语言功能。你到底想测试什么?在我看来,反思可能对你有帮助? 我也不知道如何模拟父类。这就是我问的原因。但我不认为这是不可能的 - 计算机中的东西很少。 我还是不明白你的要求。如果您使用自己的单元测试测试超类方法,然后使用自己的不同测试测试子类方法,那么有什么问题/缺少?听起来您想在子类测试中再次测试超类方法?为什么你需要这样做?还是我错过了什么 @Robse 这仅在子类仅添加新方法而不覆盖父类中的任何方法时才有效。但是当我在超类中重写一个方法时,我需要确保新方法现在可以改变超类的行为,同时又不会破坏它不应该影响的行为。跨度> the solution given by munificent 有一个 nice example。让测试层次结构类似于您的类层次结构。 【参考方案1】:使用一套反映类层次结构的单元测试。如果您有一个基类 Base 和一个派生类 Derived,那么就有测试类 BaseTests 并从该 DerivedTests 派生。 BaseTests 负责测试 Base 中定义的所有内容。 DerivedTests 继承了这些测试,还负责测试 Derived 中的所有内容。
如果您想测试 Base 中受保护的虚拟方法(即 Base 与其后代类之间的接口),创建一个测试该接口的仅测试派生类也可能有意义。
【讨论】:
【参考方案2】:只要你不重写父类的公共方法,我看不出你为什么需要在它的所有子类上测试它们。对父类的方法进行单元测试,对子类只测试新方法或覆盖的方法。
【讨论】:
【参考方案3】:您在合成中使用模拟对象的原因是,如果真实对象执行您不想设置的操作(例如使用套接字、串行端口、获取用户输入、检索大容量数据等)。您应该尽可能使用真实的对象。模拟对象仅适用于使用真实对象实现和维护测试的估计工作量大于使用模拟对象实现和维护测试的估计工作量。你的基类不应该做任何花哨的事情!
所以你不必测试继承。大概您正在使用基类的行为,因此只需像往常一样测试派生类 - 根据测试的需要调用基类和派生类的方法。这可以确保派生类的所有预期行为都经过测试。
基本上,(大多数时候)您测试派生类,就好像基类是不可见的一样。
【讨论】:
【参考方案4】:为什么要模拟基类?
如何从不存在的父类创建派生类?
像往常一样测试它,但是有父类。
我想你还没有讲完整个故事。
此外,语言功能应该可以工作(除非您使用的是 beta 版本左右),因此您无需测试该方法是否实际存在于派生类中。
【讨论】:
【参考方案5】:不,你没有。你只需要检查被覆盖的方法是否做了它们应该做的事情。它绝不应该影响您的父方法的行为。如果您的父方法开始失败,则意味着您在父级别测试它们时错过了绑定条件。
【讨论】:
我完全同意子类方法不应该影响父类方法的行为方式。这就是为什么我避免访问父类的成员变量而只使用它的公共接口。但是当子类方法调用父类中的方法时,那么在测试子类方法时我也最终测试了父类方法。 你是对的,这正是我所指的!只要您覆盖子类中的方法,就必须对其进行单元测试。它是否调用父方法这一事实并不重要,只需测试子类方法的结果是否是您期望的结果,以及父方法的行为是否符合您的要求。此外,正如@metao 指出的那样,您的父类中没有您在子类中没有捕获的额外状态设置。如果发生这种情况,那么您应该重新考虑使用组合而不是继承。以上是关于如何对继承对象进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ios XCTestCase 中对两个对象不相等进行单元测试
如何对依赖于 ActivatedRoute 参数的组件进行单元测试?