我开玩笑地为这个问题命名,因为我确定“取决于情况”,但是我有一些具体的问题。
在具有许多深层依赖项的软件中工作时,我的团队已经习惯了使用相当广泛的模拟将每个代码模块与其下的依赖项分开的习惯。
因此,令我惊讶的是Roy Osherove在此视频中建议您仅在5%的时间内使用模拟。我猜我们坐在70-90%之间。我也时常看到其他类似的指导。
我应该定义我认为是“集成测试”的两类,它们是如此不同,以至于它们实际上应该被赋予不同的名称:1)集成多个代码模块的进程内测试;以及2)进行对话的进程外测试。到数据库,文件系统,Web服务等。我关心的是类型#1,这些测试将所有代码模块都集成在进程中。
我阅读的许多社区指南都建议您应该使用大量独立的,细粒度的单元测试,以及少量的粗粒度的端到端集成测试,因为单元测试会为您提供有关确切位置的精确反馈可能已经创建了回归,但是设置繁琐的粗略测试实际上验证了系统的更多端到端功能。
鉴于此,似乎有必要经常使用模拟来隔离这些单独的代码单元。
给定一个对象模型,如下所示:
...还要考虑到我们应用程序的依赖深度比我在该图中适合的深度要深得多,因此在2-4层和5-13层之间有多层N。
如果我想测试在单元#1中做出的一些简单的逻辑决定,并且是否将每个依赖项都构造函数注入到依赖于它的代码模块中,例如将2、3和4构造函数注入到模块1中,图片,我宁愿将2、3和4的模拟物注入1。
否则,我将需要构造2、3和4的具体实例。这可能比仅仅进行一些额外的键入要困难得多。通常2、3和4会有构造器要求,要满足这些挑战可能很困难,根据图(并根据我们项目的实际情况),我将需要构造N到13的具体实例,以满足N的构造器。 2 3 3
当我需要2、3或4以某种方式运行时,这种情况变得更具挑战性,以便我可以测试#1中的简单逻辑决策。我可能需要一次理解整个对象图/树并“在逻辑上进行推理”,以使2、3或4以必要的方式运行。做myMockOfModule2.Setup(x => x.GoLeftOrRight())。Returns(new Right());通常看起来容易得多。当模块2告诉它正确时,测试模块1是否按预期响应。
如果我要一起测试2 ... N ... 13的具体实例,那么测试设置将非常大,并且几乎是重复的。测试失败可能无法很好地指出回归失败的位置。测试不会是独立的(另一个支持链接)。
当然,对底层进行基于状态的测试,而不是基于交互的测试,通常是合理的,因为这些模块很少具有任何进一步的依赖性。但似乎从定义上讲,模拟几乎是必要的,以隔离最底层之上的任何模块。
考虑到所有这些,谁能告诉我我可能会缺少什么?我们的团队过度使用模拟吗?还是在典型的单元测试指南中可能存在一些假设,即大多数应用程序中的依赖层将足够浅,因此测试集成在一起的所有代码模块确实是合理的(使我们的案例“特殊”)?或者,也许是不同的,我们的团队是否没有适当地限制我们有限的环境?
Or is there perhaps some assumption in typical unit testing guidance that the layers of dependency in most applications will be shallow enough that it is indeed reasonable to test all of the code modules integrated together (making our case "special")?
<-这个。