这实际上与语言无关。但我会在python中给你上下文。
我有这个父类
class Mammal(object):
def __init__(self):
""" do some work """
def eat(self, food):
"""Eat the food"""
way_to_eat = self._eating_method()
self._consume(food)
def _eating_method(self):
"""Template method"""
def _consume(self, food):
"""Template method"""
此处eat
是唯一的公共方法,而_consume
和_eating_method
实际上是受子类实现的受保护方法。
当您只编写Mammal
课程时,您会测试什么?
显然所有4种方法。
现在让我们介绍一个孩子
class Tiger(Mammal):
def _eating_method(self):
"""Template method"""
def _consume(self, food):
"""Template method"""
看看这堂课。它只有2个受保护的方法。
我应该测试Tiger
的所有4个方法(包括2个继承的)还是仅测试引入的更改(仅覆盖2个方法)?
理想情况是什么?
答案 0 :(得分:34)
从理论的角度来看,您只需要测试可实例化类的公共方法(使用标准OOP语言)。测试内部行为没有意义,因为你想要的只是“输入的输出”(对于特定的方法,或整个类)。你应该尽可能地尊重它,因为它迫使你提出一些关于你的班级的encapsulation以及所提供的界面的问题,这可能对你的架构具有决定性作用。
从实用的角度来看,你有时会有一些抽象的辅助类没有实现的具体子类,或者抽象类占其子类的90%以上,而且它太难了测试输出而不插入受保护的方法。在这种情况下,您可以mock一个子类。
在你直截了当的例子中,我建议你只测试班级Tiger
(并且只测试公共方法eat
)。
只是给那些想到TDD的人留言。在TDD中,您不应该在类
Mammal
之前开始编写类Tiger
,因为Mammal
应该是重构阶段的结果。所以,你当然没有对Mammal
进行任何具体测试。
答案 1 :(得分:5)
我接近这个的方式是:
Mammal
的最小可测试子类,它提供了两个受保护方法的最小实现,允许您对公共方法的行为进行单元测试。Mammal
上的公共方法,但是断言特定于该子类的行为。这应该为您提供必要的测试覆盖率,并且测试次数最少。
一种替代方法是仅测试子类,并且在其中一个子类单元测试中也断言特定于Mammal
的特征。这避免了创建特定测试子类的需要,但是有两个缺点:
Mammal
,因此由于子类中的问题,Mammal
特定代码的测试很容易失败。Mammal
的属性的测试方式和位置可能不太明显。答案 2 :(得分:0)
测试时,您应该关注代码的外部行为,而不是实现细节。我不了解背景,所以我在这里做一些很大的假设。
你真的关心(可能是抽象的)哺乳动物超类的行为吗?重用 - 通过 - 继承关系是否重要?如果您决定将继承关系替换为基于合成的策略,该怎么办?
我会专注于测试您真正关心的课程的行为:"老虎是否按预期吃东西?"而不是测试一些仅为代码重用而引入的抽象超类。