对传出查询消息进行单元测试



我为Python改编了一个取自《The Magic Tricks of testing》的例子。桑迪·梅斯著。假设我有这个:

class Gear:
def __init__(self, wheel=Wheel()):
self.wheel = wheel
def get_gear_inches(self):
self._get_ratio() * self.wheel.get_diameter()

现在我想为get_gear_inches()方法编写单元测试。在"The Magic Tricks of testing"中,Sandi Metz建议不要对wheel.get_diameter()的返回值(这是一个输出查询)设置期望,因为这会将我们绑定到实现中,而我们只关心返回的结果。所以我们只需要测试返回值,像这样:

def test_get_gear_inches():
gear = Gear()
assert gear.get_gear_inches() == 12  # For example

但是我有点困惑。

  1. 这不是一个集成测试吗?在我看来,我们正在测试两个组件(GearWheel)的行为,而不仅仅是一个。
  2. 另外,如果这个传出查询(self.wheel.get_diameter())到达db并且需要很长时间怎么办?

什么是"正确的"?测试方法是什么?


注意:我的替代方案是设置期望并嘲笑Wheel.get_diameter()的行为,像这样:

def test_get_gear_inches():
wheel_mock = Mock()
wheel_mock.get_diameter.return_value = 123  # We avoid calling the actual implementation
gear = Gear(wheel_mock)

assert Gear().get_gear_inches() == 12  # For example

但在视频中,据我所知,这是不鼓励的。

她说检查gear.wheel.diameter是反模式的,因为如果weel的实现发生了变化,那么测试就会被破坏。但是,初始化weel已经使测试变得更加脆弱,这并没有困扰她。但是,如果可能的话,更好的解决方案是将gearwheel一起测试。或者用更大的东西一起测试它们。但是,如果这些对象具有复杂的行为,并且您希望单独测试它们,那么正确的解决方案是模拟wheel。否则,当没有这样的需要时,您将测试wheelGear,因为您在其他地方测试了' wheel。所有的原则都应该只适用于特定的情况,而不应该在违背常识的情况下应用。那些教书的人并不总是提到它。