使用'真实'实用程序类而不是在TDD中进行模拟是否可以接受?

时间:2010-11-05 13:32:24

标签: unit-testing tdd

我有一个项目,我正在尝试学习单元测试和TDD实践。我发现我遇到了一些令人困惑的案例,我花了很长时间为一个几乎无处不在的实用类设置模拟。

从我读过的关于单元测试的内容来看,如果我正在测试MyClass,我应该嘲笑任何其他功能(例如由UtilityClass提供)。是否可以接受(假设UtilityClass本身有一套全面的测试)只使用UtilityClass而不是为所有不同的测试用例设置模拟?

编辑:我正在进行大量设置的其中一件事。 我正在建模地图,不同位置的不同对象。我的实用程序类的常用方法之一是GetDistanceBetween。我正在测试根据各自属性对事物产生影响的方法,例如,选择5个单位中的所有对象并且年龄超过3的测试将需要多次测试(获取范围内的旧对象,忽略旧对象)范围,忽略范围内的年轻对象,每个案例的倍数正确工作)所有这些测试需要设置'GetDistanceBetween'方法。将每个使用GetDistanceBetween(几乎每一个)的方法与该方法在不同情况下应该返回的不同结果相乘,并得到很多设置。

我可以看到,当我进一步开发时,可能会有更多实用程序类调用,大量对象以及这些模拟实用程序类上的大量设置。

5 个答案:

答案 0 :(得分:23)

规则不是“模仿一切”,而是“简化测试”。如果

,应该使用模拟
  1. 您无法合理地创建实例(读取:您需要单个方法调用,但要创建实例,您需要一个工作数据库,一个数据库连接和另外五个类。)
  2. 创建额外的课程费用很高。
  3. 其他类返回不稳定的值(如数据库中的当前时间或主键)

答案 1 :(得分:9)

TDD并非真正关于测试。它的主要好处是帮助您设计干净,易于使用的代码,以便其他人理解和更改。如果它的主要好处是测试那么你就可以在你的代码之后而不是之前编写测试,并产生相同的效果。

如果可以,我建议您不要将它们视为“单元测试”。相反,请将您的测试视为如何使用代码的示例,以及其行为的描述,以说明您的代码有价值的原因。

作为该行为的一部分,您的班级可能希望使用一些协作类。你可以嘲笑这些。

如果你的实用工具类是你班级行为的核心部分,而你的班级没有价值,或者没有它们就没有意义,那么就不要嘲笑它们。

Aaron Digulla的回答非常好;我根据这些原则重述了他的每一个答案:

  1. 协作类的行为很复杂,与您感兴趣的类的行为无关。

  2. 创建合作课程不是课堂上有价值的方面,也不需要成为课堂责任的一部分。

  3. 协作类提供了更改类的行为的上下文,因此会介绍如何使用它以及您可能期望的行为。

  4. 希望有道理!如果您喜欢它,请看一下使用这种词汇的BDD远远超过“测试”。

答案 2 :(得分:4)

理论上你应该尝试模拟所有的依赖关系,但实际上它永远不可能。例如。你不打算从标准库中嘲笑基本类。在你的情况下,如果实用程序类只包含一些基本的帮助器方法,我想我不会费心去模拟它。

如果它比这更复杂或连接到某些外部资源,你必须嘲笑它​​。您可以考虑创建一个专用的模拟构建器类,它将创建一个标准模拟(定义了一些标准存根)等,这样就可以避免在所有测试类中模拟代码重复。

答案 3 :(得分:2)

不,这是不可接受的,因为您不再孤立地测试该类,这是单元测试中最重要的方面之一。即使实用程序具有自己的一组测试,您也会依赖此实用程序对其进行测试。为了简化模拟对象的创建,您可以使用模拟框架。以下是一些受欢迎的选择:

当然,如果此实用程序类是私有的,并且只能在被测试的类的范围内使用,那么您不需要模拟它。

答案 4 :(得分:1)

是的,这是可以接受的。重要的是让UtilityClass经过彻底的单元测试,并且能够区分测试因测试类还是因为UtilityClass而失败。

隔离测试类意味着在受控环境中测试它,在一个控制对象行为方式的环境中 必须在测试设置中创建太多对象,这表明环境变得太大,因此控制不够。现在是恢复模拟对象的时候了。