使用Spring进行单元测试与集成测试

时间:2008-11-11 18:28:10

标签: java tdd junit spring-mvc integration-testing

我正在开发一个Spring MVC项目,并且我对源代码树中的所有各种组件进行了单元测试。

例如,如果我有一个控制器HomeController,需要注入LoginService,那么在我的单元测试中HomeControllerTest我只是将对象实例化为正常(外部) of Spring)并注入属性:

protected void setUp() throws Exception {
    super.setUp();
    //...
    controller = new HomeController();
    controller.setLoginService( new SimpleLoginService() );
    //...
}

这对于将每个组件作为一个独立的单元进行测试非常有用 - 除了现在我在项目中有几十个类,在编写一个类并为它编写成功的单元测试后,我一直忘记更新我的Spring MVC上下文在已部署的应用程序中进行实际连接的文件。我发现当我将项目部署到Tomcat并从非有线bean中找到一堆NullPointers时,我忘记更新上下文文件。

所以,这是我的问题:

  1. 这是我的第一个Spring项目 - 正如我所做的那样,为单个bean创建单元测试是正常的,然后创建第二套测试(集成测试)来测试一切是否按预期工作实际的应用背景?是否有既定的最佳实践?

  2. 此外,您如何将单元测试与集成测试分开?我有src中的所有源代码,test中的单元测试 - 是否应该有第二个测试文件夹(例如test-integration)用于集成测试用例?

    < / LI>

    由于这是我的第一个春季项目,我很好奇其他人通常会如何做这类事情 - 而不是重新发明轮子我宁愿问社区其他人。

7 个答案:

答案 0 :(得分:32)

我不能说是最佳实践,但这是我过去所做的。

单元测试:

  • 为非平凡的bean(即大多数与Spring相关的bean)创建单元测试
  • 在实际可行的情况下使用Mocks进行注入服务(即大部分时间都是如此)。
  • 在项目test目录中对这些测试使用标准命名约定。使用TestTestCase作为类名的前缀或后缀似乎已被广泛使用。

整合测试:

  • 创建AbstractIntegrationTestCase,设置Spring WebApplicationContext以用于集成测试条款。
  • test目录中使用命名约定进行集成测试。我已使用IntTestIntegrationTest作为这些测试的前缀或后缀。

设置三个Ant test目标:

  1. test-all(或任何您想要命名的内容):运行单元和集成测试
  2. 测试:运行单元测试(仅因为test似乎是单元测试的最常见用法
  3. 测试集成:运行集成测试。
  4. 如上所述,您可以使用对您的项目有意义的命名约定。

    至于将单元从集成测试分离到一个单独的目录中,只要开发人员及其工具可以轻松找到并执行它们,我认为这不重要。

    作为一个例子,我使用Spring工作的最后一个Java项目完全使用了上面描述的内容,集成测试和单元测试位于同一个test目录中。另一方面,Grails项目明确地将通用测试目录下的单元和集成测试目录分开。

答案 1 :(得分:6)

一些孤立的观点:

是的,这是Spring测试的常用方法 - 单独的单元测试和集成测试,前者不加载任何Spring上下文。

对于您的单元测试,可以考虑进行模拟以确保您的测试集中在一个隔离模块上。

如果你的测试是依赖大量的依赖,那么它们就不是真正的单元测试。它们是集成测试,您可以使用new而不是依赖注入来连接依赖项。当您的生产应用程序使用Spring时浪费时间和重复工作!

用于调出Spring上下文的基本集成测试非常有用。

@required注释可以帮助您确保在Spring连线中捕获所需的依赖项。

也许看看Maven会给你明确的阶段来绑定你的单位和集成测试。 Maven在Spring社区中得到了广泛的应用。

答案 2 :(得分:4)

如果你也转换到一个纯粹注释的制度,你可以用@ Component,@ Controller,@ Service和@Repository注释你所有的bean,那么很多繁琐的春季双书保存就会消失。只需将@Autowired添加到您需要注入的属性中。

参见弹簧参考手册的3.11节。 http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config

在相关的说明中,我们一直在使用KenG描述的Unit / Integratrion分区测试。在我最近的政权中,我们还引入了第三个“类”测试,“ComponentTests”。它们采用全弹簧布线,但采用有线短线实现(使用弹簧中的元件扫描滤波器和注释)。

我们这样做的原因是因为对于某些“服务”层,你最终会得到大量的手工编码布线逻辑来手动连接bean,有时甚至是荒谬的模拟对象。用于5行测试的100条线路并不罕见。组件测试缓解了这个问题。

答案 3 :(得分:2)

使用InitializingBean接口(实现方法“afterPropertiesSet”)或为bean指定init方法。 InitializingBean通常更容易,因为您不需要记住将init方法添加到bean中。

使用afterPropertiesSet确保所有内容都注入为非null,如果为null,则抛出异常。

答案 4 :(得分:0)

当我为Web应用程序创建集成测试时,我将它们放在一个单独的目录中。它们是使用jUnit或TestNG构建的,并使用Selenium之类的东西与被测系统进行交互,这些内容就像用户一样点击网页。循环将如下所示:编译,运行单元测试,构建Web应用程序,将其部署到正在运行的服务器,执行测试,取消部署应用程序以及报告结果。这个想法是测试整个系统。

答案 5 :(得分:0)

关于与集成测试分开运行单元测试,我将所有后者放入集成测试目录,并使用类似this的方法使用IDE / Ant运行它们。适合我。

答案 6 :(得分:0)

单元测试和集成测试之间的区别在于,单元测试不一定加载你的上下文,你专注于你编写的代码 - 它通过模拟任何依赖调用快速失败,即有和没有例外在里面。 但是在集成测试的情况下,您可以加载上下文并像实际场景一样执行端到端测试。