何时应该移除模拟?

3

在TDD(测试驱动开发)中,有时候当依赖接口的实现不可用时,我会使用模拟对象。因此,我模拟这些依赖并测试我的工作。

现在,这些依赖的实现是可用的。那么我应该删除模拟对象还是将它们转换为spy或类似的东西?我认为只有在删除这些模拟对象之后才能进行集成测试,否则我可能需要复制它们。我有点困惑,请给出任何建议。


1
在我看来,模拟是一种平衡行为,我通常会模拟更复杂和非确定性的接口。 - simonzack
2个回答

2
就单元测试而言——永远不要。通常这是因为你想保持单元测试的独立性:
  • 你的单元测试(就像其他任何类一样)通常应该只有一个改变/中断的原因。当出现错误时,你希望将可能的罪魁祸首减少到最少。由于某个依赖项可能失败、另一个依赖项可能失败,或者最终实际测试的类可能失败,导致单元测试失败是不可取的。

事实上,这相当困难,因为即使更改依赖项的接口也会导致使用该依赖项的类的单元测试发生变化。然而,你要避免的是,某个人其他团队更改了你正在使用的某个依赖项的实现,结果你的测试失败,显然毫无原因。这同样是高度不可取的。

模拟对象应该用来隔离你的单元。当编写不同类型的测试(比如集成测试)时,你不需要隔离。你需要真正的组件协作。这是使用实际实现而不是模拟对象的原因之一——但是!——这并不否定你的单元测试。它们应该保持独立。


我想我明白了你的意思,似乎我应该保留两种单元测试方式——“模拟依赖项的单元测试”和“使用真实对象检查集成的单元测试”。看起来我的单元测试代码将会翻倍。 - Rahul Kulshreshtha
@RahulKulshreshtha:没错。你需要两种类型的测试。单元测试 - 用于验证低级行为(单元),集成测试则是为了查看类是否按预期工作。集成测试通常会测试更大的过程(例如,从数据库获取实体是否被解析并保存到其他数据库),而单元测试将在隔离的过程部分检查(例如,解析器逻辑和边缘情况)。 - k.m

1

像往常一样:这取决于具体情况。

如果您使用了模拟数据,则在测试期间您将会针对已定义的接口进行测试,因此您的单元测试更加专注,并且在进行内部重构时减少了出现断裂的可能性。

如果您使用实际依赖项,则您的单元测试不够专注(它们可能是集成测试)。因此,这些测试通常速度较慢、设置更加困难,并且在进行重构时更容易出现问题。另一方面,由于您正在针对实际实现进行测试,所以您更有可能发现由于实际实现行为与您预期不同而导致的错误。


1
通常情况下,您不应该需要删除测试,而是可能需要同时使用两种测试。通过同时使用单元测试和集成测试,通常更容易找出问题发生的位置。即使您的单元测试和集成测试基本相同,只是在其中一个中使用了模拟,这也是正确的。 - Daniel Rose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接