- 内容提要
- 作者简介
- 译者简介
- 前言
- HTTP
- Servlet 和 JSP
- 下载 Spring 或使用 STS 与 Maven/Gradle
- 手动下载 Spring
- 使用 STS 和 Maven/Gradle
- 下载 Spring 源码
- 本书内容简介
- 下载示例应用
- 第 1 章Spring 框架
- 第 2 章模型 2 和 MVC 模式
- 第 3 章Spring MVC 介绍
- 第 4 章基于注解的控制器
- 第 5 章数据绑定和表单标签库
- 第 6 章转换器和格式化
- 第 7 章验证器
- 第 8 章表达式语言
- 第 9 章JSTL
- 第 10 章国际化
- 第 11 章上传文件
- 第 12 章下载文件
- 第 13 章应用测试
- 附录 A Tomcat
- 附录 B Spring Tool Suite 和 Maven
- 附录 C Servlet
- 附录 D JavaServer Pages
- 附录 E 部署描述符
13.6 应用 Spring MVC Test 进行集成测试
集成测试用来测试不同的模块是否可以一起工作。它还确保两个模块之间数据的传递。使用 Spring 框架依赖注入容器,必须检查 bean 依赖注入。
若没有合适的工具,集成测试可能需要很多时间。想象一下,如果你正在建立一个网上商店,你必须使用网络浏览来测试购物车是否正确计算。每次更改代码时,你必须启动浏览器,登录系统,将几个项目添加到购物车,并检查总数是否正确。每次迭代可以轻易地花费 5 分钟!
好在,Spring 提供了一个用于集成测试的模块:Spring Test。
Spring 的 MockHttpServletRequest、MockHttpServletResponse 和 ModelAndViewAssert 类适用于对 Spring MVC 控制器进行单元测试,但它们缺少与集成测试相关的功能。例如,它们直接调用请求处理方法,无法测试请求映射和数据绑定。它们也不测试 bean 依赖注入,因为 SUT 类使用 new 运算符实例化。
对于集成测试,您需要一组不同的 Spring MVC 测试类型。以下小节讨论集成测试的 API 并提供一个示例。
13.6.1 API
作为 Spring 的一个模块,Spring MVC Test 提供了一些实用程序类,可以方便地在 Spring MVC 应用程序上执行集成测试。bean 是使用 Spring 依赖注入器创建的,并从 ApplicationContext 中获取,就像在一个真正的 Spring 应用程序中一样。
MockMvc 类位于 org.springframework.test.web.servlet 包下,是 Spring MVC Test 中的主类,用于帮助集成测试。此类允许你使用预定义的请求映射来调用请求处理方法。这里是一种常见的创建 MockMvc 实例的方法:
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();
这里,webAppContext 是 WebApplicationContext 实例的一个引用,WebApplicationContext 是第 2 章中讨论的 ApplicationContext 的子类,每个 Spring 开发人员都应该熟悉。要获取一个 WebApplicationContext,你必须在测试类中声明这一点。
@Autowired private WebApplicationContext webAppContext;
MockMvcBuilder 读取一个 Spring 配置文件或为测试类定义的文件。我将讨论如何指定测试类的配置文件,但首先我想讨论 MockMvc。
MockMvc 是一个非常简单的类。事实上,它只有一个方法:perform,用于通过 URI 间接调用 Spring MVC 控制器。
perform 方法具有以下签名:
ResultActions perform(RequestBuilder requestBuilder)
要测试请求处理方法,你需要创建一个 RequestBuilder。好在,MockMvcRequestBuilders 类提供了与 HTTP 方法具有相同名称的静态方法:get、post、head、put、patch、delete 等。要使用 HTTP GET 方法测试控制器,你可以调用 get 方法,要使用 POST 测试,则调用 post 方法。这些静态方法也很容易使用,你只需要传递一个字符串——控制器的请求处理方法的 URI。
例如,要调用名为 getEmployee 的请求处理方法,你将编写如下代码:
ResultActions resultActions = mockMvc.perform(get(“/ getEmployee”));
当然,你必须导入 MockMvcRequestBuilders 的静态 get 方法。
要验证测试是否成功,你需要调用 ResultActions 的 andExpect 方法。andExpect 方法签名如下:
ResultAction andExpect(ResultMatcher matcher)
注意,andExpect 返回 ResultActions 的另一个实例,这意味着可以链式调用多个 AndExpect,你可以在稍后的示例中看到这一点。
MockMvcResultMatchers 类提供了静态方法来轻松创建 ResultMatcher。MockMvcResultMatchers 属于 org.springframework.test.web.servlet.result 包。表 13.4 显示了它的一些方法。
表 13.4 MockMvcResultMatchers 的主要方法
方法 | 返回类型 | 描述 |
---|---|---|
cookie | CookieResultMatchers | 返回一个 ResultMatchers,用来断言 cookie 值 |
header | HeaderResultMatchers | 返回一个 ResultMatchers,用来断言 HTTP 响应头部 |
model | ModelResultMatchers | 返回一个 ResultMatchers,用来断言请求处理的模型 |
status | StatusResultMatchers | 返回一个 ResultMatchers,用来断言 HTTP 响应状态 |
view | ViewResultMatchers | 返回一个 ResultMatchers,用来断言请求处理的视图 |
例如,要确保控制器方法的请求映射正确,可以使用状态方法:
mockMvc.perform(get("/ getBook")).andExpect(status().isOk());
isOK 方法断言响应状态代码是 200,可以看到 MockMvc 及其相关类使得集成测试控制器变的非常容易。
13.6.2 Spring MVC 测试类的框架
了解了 Spring MVC Test 中的一些重要的 API,现在来看下 Spring MVC 测试类的框架。
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("...")
public class ProductControllerTest {
@Autowired
private WebApplicationContext webAppContext;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();
}
@After
public void cleanup(){
}
@Test
public void test1() throws Exception {
mockMvc.perform(...).andExpect(...);
}
@Test
public void test2() throws Exception {
mockMvc.perform(...).adnExpect(...);
}
...
}
首先,看下你要导入的类型。在导入列表的顶部,是来自 JUnit 和 Spring MVC Test 的类型。像单元测试类一样,Spring MVC 测试类可以包括用 @Before 和 @After 注解的方法。两种注解类型都是 JUnit 的一部分。
接下去,测试框架开始与单元测试有所不同。首先是测试类运行器。你需要一个 SpringJUnit4ClassRunner.class 在 @RunWith 注解内:
@RunWith(SpringJUnit4ClassRunner.class)
这个 runner 允许你使用 spring。
然后,你需要添加如下注解类型:
@WebAppConfiguration
@ContextConfiguration("...")
WebAppConfiguration 注解类型用于声明为集成测试加载的 ApplicationContext 应该是 WebApplicationContext 类型。ContextConfiguration 注解类型告诉测试运行器如何加载和配置 WebApplicationContext。
除以上,测试类中还需要两个对象:
private WebApplicationContext webAppContext;
private MockMvc mockMvc;
13.6.3 示例
以下示例展示如何对 Spring MVC 控制器开展集成测试。
清单 13.26 中的配置文件展示了将被扫描的包。这个文件是一个典型的 Spring MVC 配置文件,但减去了任何资源映射和视图解析器。但是,你可以使用实际的配置文件。
清单 13.26 test-config.xml 文件
< ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
< context:component-scan base-package="controller"/>
< context:component-scan base-package="service"/>
< mvc:annotation-driven/>
< /beans>
此示例中的 SUT 是清单 13.27 中的 EmployeeController 类。类中只有一个请求处理方法,getHighestPaid,它映射到/highest-paid。
清单 13.27 EmployeeController 类
package controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import service.EmployeeService;
import domain.Employee;
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@RequestMapping(value="/highest-paid/{category}")
public String getHighestPaid(@PathVariable int category, Model model)
{
Employee employee = employeeService.getHighestPaidEmployee( category);
model.addAttribute("employee", employee);
return "success";
}
}
清单 13.28 展示了 EmployeeController 的测试类。
清单 13.28 EmployeeControllerTest 类
package com.example.controller;
import static org.springframework.test.web.servlet.request.
→ MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.
→ MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.
→ MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.
→ MockMvcResultMatchers.status;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("test-config.xml")
public class EmployeeControllerTest {
@Autowired
private WebApplicationContext webAppContext;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext)
.build();
}
@After
public void cleanUp() {
}
@Test
public void testGetHighestPaidEmployee() throws Exception {
mockMvc.perform(get("/highest-paid/2"))
.andExpect(status().isOk())
.andExpect(model().attributeExists("employee"))
.andDo(print());
}
}
EmployeeControllerTest 类包含一个 setUp 方法,它创建一个 MockMvc 对象。 testGetHighestPaidEmployee 方法执行测试,并期望响应状态代码为 200,并且模型具有 employee 属性。
测试方法还调用 andDo(print()) 在响应对象中打印各种值。如果你的测试成功通过,你应该会看到类似的结果。
MockHttpServletRequest:
HTTP Method = GET
Request URI = /highest-paid/2
Parameters = {}
Headers = {}
Handler:
Type = controller.EmployeeController
Method = public java.lang.String
controller.EmployeeController.getHighestPaid(int,org.springframe-
work.ui.Model)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = success
View = null
Attribute = employee
value = Xiao Ming ($200000)
errors = []
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = success
Redirected URL = null
Cookies = []
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论