Spring Framework 3.2 RC1:Spring MVC 测试框架

工程 | Rossen Stoyanchev | 2012年11月12日 | ...

[提示框 标题=2012年12月19日更新]最终的 Spring Framework 参考文档包含了迁移指南以及关于 Spring MVC 测试的完整章节。[/提示框]

上周Juergen Hoeller 宣布发布 Spring Framework 3.2 RC1,Sam Brannen 讨论了其spring-test 模块中令人兴奋的补充,例如对 `WebApplicationContext` 的支持以及即将推出的加载上下文层次结构的计划。今天,我将继续讨论这个主题,并介绍另一个令人兴奋的 `spring-test` 新增功能。在 3.2 RC1 中,我们添加了对客户端和服务器端 Spring MVC 应用程序进行测试的一流支持。

背景

此处讨论的 Spring MVC 测试框架源自 Github 上的独立项目,该项目的功能在一年多的时间里不断发展,并不断收到许多用户的反馈。感谢所有早期采用者,所有贡献者报告问题的人,发表评论的人,以及所有撰写博客或发表演讲的人。

从 Spring 3.2 RC1 开始,独立项目的代码已添加到 Spring Framework,并在 `spring-test` 模块中可用,包名称略有修改,并支持 3.2 的特定功能,例如异步请求等。独立项目将继续存在,用于针对 Spring MVC 3.1 进行应用程序测试。

言归正传,让我们更仔细、更详细地了解一下。

服务器端支持

您今天如何测试 Spring MVC 控制器?很可能通过简单的单元测试,可能涉及 `MockHttpServletRequest` 和 `-Response`。这很容易做到,但测试还不够充分。控制器具有注解,这些注解表达了它们的映射方式、需要提取、转换和验证哪些请求数据、是否写入响应正文、如何处理异常等等。如果您只编写简单的单元测试,框架由于这些注解而执行的所有操作都将未经测试。

如果您能够重写这些控制器单元测试,但不是直接调用控制器,而是通过 DispatcherServlet 进行调用,就像在运行时发生的那样,那将会怎样呢?如果您能够使用流畅的 API 来指定要执行的请求和您期望的响应,那又将会怎样呢?所有这些都不需要 servlet 容器。这就是 Spring MVC Test 的作用。这是一个例子


@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("servlet-context.xml")
public class SampleTests {

  @Autowired
  private WebApplicationContext wac;

  private MockMvc mockMvc;

  @Before
  public void setup() {
    this.mockMvc = webAppContextSetup(this.wac).build();
  }

  @Test
  public void getFoo() throws Exception {
    this.mockMvc.perform(get("/foo").accept("application/json"))
        .andExpect(status().isOk())
        .andExpect(content().mimeType("application/json"))
        .andExpect(jsonPath("$.name").value("Lee"));
  }
}

[提示框 标题=静态导入]流畅的 API 依赖于这些静态导入:`MockMvcBuilders.*` `MockMvcRequestBuilders.*` `MockMvcResultMatchers.*` 为了获得代码完成辅助功能,请在 Eclipse 首选项中将它们添加为“收藏类型”,或者只需记住以 `MockMvc*` 开头的类即可。[/提示框]

如您所见,我们使用新的 `@WebAppConfiguration` 注解来加载我们的 Spring MVC 配置。然后,我们将生成的 `WebApplicationContext` 注入到测试类的字段中,并用它来创建一个 `MockMvc`,然后使用它来执行请求和定义期望。

[提示框 标题=上下文缓存]TestContext 框架在测试套件中甚至在 JVM 中缓存加载的 Spring 配置。因此,测试速度应该非常理想。[/提示框]

与现有的控制器单元测试一样,Spring MVC Test 基于 `spring-test` 中的模拟请求和响应,不需要运行 servlet 容器。主要区别在于实际的 Spring MVC 配置是通过 TestContext 框架加载的,并且请求是通过实际调用 `DispatcherServlet` 和运行时使用的所有相同的 Spring MVC 基础架构来执行的。

同样类似于现有的控制器单元测试,您可以考虑使用模拟服务注入控制器,以便专注于测试 Web 层,例如避免访问数据库。因此,您可以加载创建模拟的配置,而不是加载实际的业务和持久性服务。例如


@Configuration
public class MyConfig {

    @Bean
    public FooService fooService() {
        return Mockito.mock(FooService.class);
    }

}

或者在 XML 配置中


<bean class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="org.example.FooService"/>
</bean>

鉴于我们不是在实际的 servlet 容器中运行,到底哪些功能会工作,哪些功能不会工作呢?在大多数情况下,所有功能都会像运行时那样工作。您甚至可以注册 Servlet 过滤器,启用 Spring Security 等功能。大多数渲染技术(如 JSON/XML、Freemarker、Velocity、Thymeleaf、Excel、PDF 等)都会工作。唯一被排除的渲染技术是 JSP,因为它需要 servlet 容器。对于 JSP,您仍然可以验证请求被转发到的 JSP,模型中有哪些属性,是否引发了任何异常等等。

客户端 REST 测试

客户端 REST 测试的理念是什么?如果您有使用 `RestTemplate` 的代码,您可能希望测试它,为此您可以针对正在运行的服务器或模拟 `RestTemplate`。客户端 REST 测试支持提供了一种第三种替代方法,即使用实际的 `RestTemplate`,但将其与自定义 `ClientHttpRequestFactory` 配合使用,该工厂会检查实际请求的期望并返回存根响应。


RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);

mockServer.expect(requestTo("/greeting"))
  .andRespond(withSuccess("Hello world", "text/plain"));

// use RestTemplate ...

mockServer.verify();

[提示框 标题=静态导入]流畅的 API 需要静态导入
`MockRestRequestMatchers.*` `MockRestResponseCreators.*` 为了获得代码完成辅助功能,请在 Eclipse 首选项中将它们添加为“收藏类型”,或者只需记住以 `"MockRest*"` 开头的类即可。[/提示框]

如您所见,我们创建了一个 `RestTemplate` 实例,并将其传递给 `MockRestServiceServer` 进行配置。然后,我们定义预期请求的特性,并提供要返回的存根响应。我们可以定义任意数量的预期请求和存根响应。在测试结束时,我们可以使用 `verify` 方法来检查是否执行了所有预期请求。

后续步骤

我们还可以讨论更多内容,但最好您自己尝试一下,使用 Spring Framework 3.2 RC1 或 Github 上的独立项目(适用于 Spring Framework 3.1)。

我最近自己也进行了这项练习,为 spring-mvc-showcase 的所有控制器方法添加了一套全面的测试。这是一个有用的练习,因为它帮助我发现了一个错误。因此,我相信它对其他人也有用。

如果您想要更多示例,包括Spring Framework 中还有许多演示测试 带有异步请求的测试带有过滤器的测试JSON 响应XML 响应等等。

获取 Spring Newsletter

与 Spring Newsletter 保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部