容器内测试与模拟对象进行集成测试

容器内测试通常与使用模拟对象进行测试相反。 但是,由于模拟对象只是模仿真实对象的行为,因此容器内测试不是在其真实环境中真正测试系统的唯一方法吗?

作为容器内测试和模拟对象的部分替代,Spring提供了TestContext框架,可以很好地初始化Spring,而无需启动实际的应用程序容器(在我的例子中是Web应用程序服务器)。 但是,这是一种有限的方法,因为它只初始化特定于Spring的function,而不支持特定于应用程序服务器的function。 所以你无法测试一切。 此外,由于它与实际Web执行中使用的默认WebApplicationContext不是100%相同,这种方法是不是有点hackyish? 这不好吗?

对于容器内测试,至少有Cactus (过时), Jeeunit (一个非常小的项目)和JBoss Arquillian (仍然是alpha,但看起来很有希望)。 我没有看到任何这些项目被广泛使用,所以容器内测试有什么不好吗? 容器内测试经常提到的主要缺点是执行速度慢。 但是,当在持续集成环境和相对较小的项目中运行时,这应该不是问题。

总结一下:我们应该进行容器内还是容器外测试?为什么? 使用模拟对象或替代初始化机制(如在Spring TestContext中)进行集成测试会不会感觉不舒服?

一个子注释:我最近询问了集成测试的分类 ,这可能是相关的。

但是,由于模拟对象只是模仿真实对象的行为,因此容器内测试不是在其真实环境中真正测试系统的唯一方法吗?

我认为简短的答案是肯定的,但是……我认为你的“整合测试分类”问题非常重要。 单元和集成测试都很重要,尽管它们具有不同的function。

unit testing与代码密切相关,如果启动和运行速度非常快,应该经常由开发人员迭代代码运行,并且通常在很大程度上使用模拟。 我们的想法是测试有问题的代码,而不是它的依赖关系或集成点。 将unit testing全部放在容器内的问题在于它们的运行频率较低,或者它们会浪费太多的开发人员时间。

我们在另一个项目的其他地方隔离了我们的容器内/集成测试,并依赖于代码项目。 它们旨在尽可能地模拟生产配置。 这些测试需要更长的时间来设置,运行时间更长,并且更有用的是像cruisecontrol这样运行。 它们是手工运行的,特别是当我们关闭一个版本或开发稳定后。 我常常在午餐或开会时开始进行集成测试。 当集成测试发现错误时,我们会尝试编写一个unit testing来演示模拟的错误 – 这通常很难并且是不可能的。

我们通常在unit testing中进行一些小的容器内测试,以确保弹簧接线工作或测试一些基本function,但其余的集成测试是在另一个项目中完成的。

所有这些都说,两者之间没有明显的区别。 有时我们移动unit testing只处理大量数据并花费很长时间进行集成测试,有时集成测试运行得足够快,并且足够有价值,可以与代码一起包含。

我要说我们应该进行容器内和容器外测试。 我在容器内测试时发现的主要问题是自动化所有东西要做得更多。 你可以通过Spring的集成测试支持获得一些更便宜的胜利,但是我们不应该欺骗自己,这涵盖了部署容器中测试的所有内容。

关于模拟的话题,我发现它们可以在Spring的集成测试中发挥作用,但我更有可能使用带有预制结果的假/存根服务进行集成和容器内测试(我称之为系统测试) )。

如果您不确定模拟和存根之间的区别,请查看Martin Fowler的这篇文章 。