如何为 SpringMVC 编写单元测试:普通 Controller 测试(转)


前一篇文章我们已经知道如何配置使用了 SpringMVC 测试框架的单元测试。

现在我们就该亲身实践下如何为普通 Controller 编写单元测试了。

接下来一个很明显的问题就是:

什么是普通 Controller

其实,就这篇文章来说普通 Controller 就是指负责渲染界面或处理请求的 Controller。

如果你没读过前面的配置篇,那么我建议你先读一下。

使用 Maven 获取必须依赖

我们可以通过为我们的样例程序中的 POM 文件添加以下依赖声明来获取必须依赖:

Jackson 2.2.1 (core 和 databind 模块)。我们使用 Jackson 把对象转化为字符串。 
Hamcrest 1.3。使用它为返回内容写断言。 
JUnit 4.11 (不需要包括 hamcrest-core 依赖). 
Mockito 1.9.5 
Spring Test 3.2.3.RELEASE 
体现在 pom.xml 文件中的相关配置如下:

 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.2.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.2.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> <exclusions> <exclusion> <artifactId>hamcrest-core</artifactId> <groupId>org.hamcrest</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>1.9.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.2.3.RELEASE</version> <scope>test</scope> </dependency>

接下来让我们看看如何使用 SpringMVC 测试框架为普通 Controller 写单元测试。

为 Controller 中方法编写单元测试

我们为 Controller 中方法写的每一个测试都包括以下几个步骤:

往 Controller 中方法发送一个请求。 
验证返回的内容是不是符合预期。 
SpringMVC 为我们更便捷的实现这几步提供了几个核心类。基本描述如下:

我们可以使用 MockMvcRequestBuilders 类的静态方法构建请求对象。更确切的说, 我们可以新建一个请求构建对象并把它当作参数传递给请求方法。 
MockMvc 类是整个测试的入口。我们可以调用它的 perform(RequestBuilder requestBuilder) 方法执行请求。 
我们可以使用 MockMvcResultMatchers 类的表态方法为接收到的返回对象写断言。 
接下来让我们看几个如何在测试中使用它们的例子。我们会如下几个方法编写单元测试:

第一个 Controller 方法会为 Todo 对象渲染一个列表页。 
第二个 Controller 方法是为单个 Todo 对象渲染详情页。 
第三个 Controller 方法接收表单并在数据库中新建 Todo 对象记录。 
渲染 Todo 对象列表页

让我们先了解下渲染 Todo 对象列表页的代码。

预期行为

用来展示列表的方法实现主要包括以下几步:

接收发送到 ‘/’ 地址的 GET 请求。 
调用 TodoService 接口的 findAll() 方法获取全部 Todo 对象。这个方法会返回一个包含 Todo 对象的列表。 
把接收到的列表添加到 Model 对象中。 
返回待渲染视图名称。 
相关的 TodoController 类中代码如下:

import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.List; @Controller public class TodoController { private final TodoService service; @RequestMapping(value = "/", method = RequestMethod.GET) public String findAll(Model model) { List<Todo> models = service.findAll(); model.addAttribute("todos", models); return "todo/list"; } }

 

现在我们可以开始为这个方法写单元测试了。

测试: 查询到 Todo 对象列表时

我们可以通过以下几步为这个 Controller 方法编写单元测试:

创建 Service 中方法被调用时的返回数据。我们使用一个叫测试数据构建器的概念来表示创建测试数据。 
将冒烟对象的 findAll() 方法被调用时的返回对象配置成前面创建的测试数据。 
往 ‘/’ 地址发送一个 GET 请求。 
确认返回的 HTTP 状态码是 200。 
确认返回的视图名称是 ‘todo/list’。 
确认请求被定向到地址 ‘/WEB-INF/jsp/todo/list.jsp’。 
确认 Model 对象中的 todos 属性中有两个元素。 
确认 Model 对象中的 todos 属性中的对象都是正确的。 
确认冒烟对象的 findAll() 方法仅被调用过一次。 
确认冒烟对象的其它方法在测试过程中没被调用过。 
单元测试源代码如下:

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; 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; import java.util.Arrays; import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest { private MockMvc mockMvc; @Autowired private TodoService todoServiceMock; //此处添加 WebApplicationContext 字段 //setUp() 方法 @Test public void findAll_ShouldAddTodoEntriesToModelAndRenderTodoListView() throws Exception { Todo first = new TodoBuilder() .id(1L) .description("Lorem ipsum") .title("Foo") .build(); Todo second = new TodoBuilder() .id(2L) .description("Lorem ipsum") .title("Bar") .build(); when(todoServiceMock.findAll()).thenReturn(Arrays.asList(first, second)); mockMvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(view().name("todo/list")) .andExpect(forwardedUrl("/WEB-INF/jsp/todo/list.jsp")) .andExpect(model().attribute("todos", hasSize(2))) .andExpect(model().attribute("todos", hasItem( allOf( hasProperty("id", is(1L)), hasProperty("description", is("Lorem ipsum")), hasProperty("title", is("Foo")) ) ))) .andExpect(model().attribute("todos", hasItem( allOf( hasProperty("id", is(2L)), hasProperty("description", is("Lorem ipsum")), hasProperty("title", is("Bar")) ) ))); verify(todoServiceMock, times(1)).findAll(); verifyNoMoreInteractions(todoServiceMock); } }

 

渲染 Todo 对象详情页

在写具体测试代码前,让我们先看看待测方法的实现。

预期行为

用以展示单个 Todo 对象信息的 Controller 方法实现中主要包含以下几步:

接收发送到 ‘/todo/{id}’ 地址的 GET 请求。{id} 是一个用于标识被请求 Todo 对象主键的地址变量。 
它通过调用 TodoService 接口的 findById() 方法获取被请求的 Todo 对象,方法参数是被请求 Todo 对象的主键。这个方法会返回找到的 Todo 对象。如果没找到对应对象,这个方法会抛出 TodoNotFoundException 异常。 
它会把找到的 Todo 对象添加到 Model 对象中。 
返回待渲染的视图对象。 
Controller 方法源代码如下:

 import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; @Controller public class TodoController { private final TodoService service; @RequestMapping(value = "/todo/{id}", method = RequestMethod.GET) public String findById(@PathVariable("id") Long id, Model model) throws TodoNotFoundException { Todo found = service.findById(id); model.addAttribute("todo", found); return "todo/view"; } }

下一个问题就是:

什么时候抛出 TodoNotFoundException 异常?

在本系列指南前面我们提到过,我们为 Controller 类抛出的异常创建过一个处理类。这个处理类的配置信息大体是这样的:

@Bean public SimpleMappingExceptionResolver exceptionResolver() { SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); Properties exceptionMappings = new Properties(); exceptionMappings.put("net.petrikainulainen.spring.testmvc.todo.exception.TodoNotFoundException", "error/404"); exceptionMappings.put("java.lang.Exception", "error/error"); exceptionMappings.put("java.lang.RuntimeException", "error/error"); exceptionResolver.setExceptionMappings(exceptionMappings); Properties statusCodes = new Properties(); statusCodes.put("error/404", "404"); statusCodes.put("error/error", "500"); exceptionResolver.setStatusCodes(statusCodes); return exceptionResolver; }

正如我们看到的,如果抛出一个 TodoNotFoundException 异常,应用会返回 404 状态码并渲染 ‘error/404′ 视图。

为这个 Controller 方法编写单元测试时很明显包括以下两步:

必须有一个用例用来确保当找不到 Todo 对象时应用能正确执行。 
必须有一个用例用来确保当 Todo 对象被找到时也能正确执行。 
现在看看这个测试应该怎么写。

测试 1: 查询不到 Todo 对象时

首先,我们必须要确保我们的应用在找不到被查询 Todo 对象时也能正常工作。我们可以通过以下几步来进行测试:

配置冒烟对象,让它在 findById() 方法以参数 1L 被调用时抛出 TodoNotFoundException 异常。 
往 ‘/todo/1′ 地址发送一个 GET 请求。 
确认返回的 HTTP 状态码是 404。 
确保返回的视图名称是 ‘error/404′。 
确保请求被定向到地址 ‘/WEB-INF/jsp/error/404.jsp’。 
确认 TodoService 接口的 findById() 方法仅被调用过一次而且参数为 1L。 
确认冒烟对象的其它方法在测试期间没被调用过。 
这个测试用例的代码如下:

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; 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; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest { private MockMvc mockMvc; @Autowired private TodoService todoServiceMock; //Add WebApplicationContext field here //The setUp() method is omitted. @Test public void findById_TodoEntryNotFound_ShouldRender404View() throws Exception { when(todoServiceMock.findById(1L)).thenThrow(new TodoNotFoundException("")); mockMvc.perform(get("/todo/{id}", 1L)) .andExpect(status().isNotFound()) .andExpect(view().name("error/404")) .andExpect(forwardedUrl("/WEB-INF/jsp/error/404.jsp")); verify(todoServiceMock, times(1)).findById(1L); verifyZeroInteractions(todoServiceMock); } }

测试 2: 查询到 Todo 对象时

接上文,现在我们需要写一个确保应用在能查询到 Todo 对象时也能正确工作的测试用例。基本步骤如下:

创建 Service 中方法被调用时返回的 Todo 对象。同样,我们还是通过测试数据构建器创建测试对象。 
配置冒烟对象,让它在 findById() 方法以 1L 参数被调用时返回前面创建的 Todo 对象。 
往 ‘/todo/1′ 地址发送 GET 请求。 
确认返回的 HTTP 状态码是 200。 
确保返回的视图名称是 ‘todo/view’。 
确保请求被定向到地址 ‘/WEB-INF/jsp/todo/view.jsp’。 
确认 Model 对象中的 Todo 对象主键是 1L。 
确认 Model 对象中的 Todo 对象描述字段值为 ‘Lorem ipsum’。 
确认 Model 对象中的 Todo 对象名称字段值为 ‘Foo’。 
确保冒烟对象的 findById() 方法仅被调用过一次,而且参数为 1L。 
确保冒烟对象中的其它方法在测试过程中没被调用过。 
测试用例代码如下:

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; 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; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest { private MockMvc mockMvc; @Autowired private TodoService todoServiceMock; //Add WebApplicationContext field here //The setUp() method is omitted. @Test public void findById_TodoEntryFound_ShouldAddTodoEntryToModelAndRenderViewTodoEntryView() throws Exception { Todo found = new TodoBuilder() .id(1L) .description("Lorem ipsum") .title("Foo") .build(); when(todoServiceMock.findById(1L)).thenReturn(found); mockMvc.perform(get("/todo/{id}", 1L)) .andExpect(status().isOk()) .andExpect(view().name("todo/view")) .andExpect(forwardedUrl("/WEB-INF/jsp/todo/view.jsp")) .andExpect(model().attribute("todo", hasProperty("id", is(1L)))) .andExpect(model().attribute("todo", hasProperty("description", is("Lorem ipsum")))) .andExpect(model().attribute("todo", hasProperty("title", is("Foo")))); verify(todoServiceMock, times(1)).findById(1L); verifyNoMoreInteractions(todoServiceMock); } }

 

处理表单并在数据库中添加 Todo 记录

首先,在编写测试用例前还是看一下待测试 Controller 方法的预期行为。

预期行为

负责处理表单并入库的 Controller 方法基本实现步骤如下:

接收发送到 ‘/todo/add’ 地址的 POST 请求。 
校验传递过来的 BingdingResult 参数是正确的,否则返回表单视图名称。 
以表单对象为参数调用 TodoService 接口的 add() 方法进行 Todo 对象入库。 
创建返回信息并将返回信息作为参数传递给 RedirectAttributes 中。 
把入库的 Todo 对象主键添加到 RedirectAttributes 中。 
把请求重定向到 Todo 对象详情页并渲染。 
位于 TodoController 类中的相关代码如下:

import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.validation.Valid; import java.util.Locale; @Controller @SessionAttributes("todo") public class TodoController { private final TodoService service; private final MessageSource messageSource; @RequestMapping(value = "/todo/add", method = RequestMethod.POST) public String add(@Valid @ModelAttribute("todo") TodoDTO dto, BindingResult result, RedirectAttributes attributes) { if (result.hasErrors()) { return "todo/add"; } Todo added = service.add(dto); addFeedbackMessage(attributes, "feedback.message.todo.added", added.getTitle()); attributes.addAttribute("id", added.getId()); return createRedirectViewPath("todo/view"); } private void addFeedbackMessage(RedirectAttributes attributes, String messageCode, Object... messageParameters) { String localizedFeedbackMessage = getMessage(messageCode, messageParameters); attributes.addFlashAttribute("feedbackMessage", localizedFeedbackMessage); } private String getMessage(String messageCode, Object... messageParameters) { Locale current = LocaleContextHolder.getLocale(); return messageSource.getMessage(messageCode, messageParameters, current); } private String createRedirectViewPath(String requestMapping) { StringBuilder redirectViewPath = new StringBuilder(); redirectViewPath.append("redirect:"); redirectViewPath.append(requestMapping); return redirectViewPath.toString(); } }

 

我们可以看到,这个方法用了一个 TodoDTO 对象来表示表单对象。TodoDTO 类只是一个简单的数据传输类,它的代码大致如下:

import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty; public class TodoDTO { private Long id; @Length(max = 500) private String description; @NotEmpty @Length(max = 100) private String title; //Constructor and other methods are omitted. }

 

这个类中声明了如下一些校验约束:

Todo 对象中的 title 属性不能为空。 
description 属性的最大长度是 500 字符。 
title 属性的最大长度是 100 字符。 
如果我们仔细思考下我们该为这个方法写的测试,就会发现我们至少有以下几点需要做的:

在参数校验失败时 Controller 方法需要能正常工作。 
校验通过时也能正常工作并正常入库。 
现在让我们看看这个测试应该怎么写。

测试 1: 校验失败时

首先,我们需要测一下校验失败时 Controller 方法也能正常工作。这个测试我们可以这么干:

创建 title 属性包含 101 字符。 
创建 description 属性包含 501 字符。 
通过以下几步往 ‘/todo/add’ 地址发送 POST 请求: 
把请求的 Content-Type 设置成 ‘application/x-www-form-urlencoded’。 
把前面提到的 title 和 description 当作请求参数发送过去。 
在 session 中设置一个 TodoDTO 对象。这是必须的因为我们的 Controller 有一个 @SessionAttributes 注解。 
校验返回的 HTTP 状态码是 200。 
校验返回的视图名称是 ‘todo/add’。 
校验请求被定向到地址 ‘/WEB-INF/jsp/todo/add.jsp’。 
校验 model 对象中有 title 和 description 参数错误的提示信息。 
确保 model 中的 id 属性是空。 
确保 model 中的 description 属性是正确的。 
确保 model 中的 title 属性是正确的。 
确保冒烟对象中的方法在测试过程中没被调用过。 
这个测试的源代码大体如下:

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; 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; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest { private MockMvc mockMvc; @Autowired private TodoService todoServiceMock; //此处添加 WebApplicationContext 字段 //setUp() 方法 @Test public void add_DescriptionAndTitleAreTooLong_ShouldRenderFormViewAndReturnValidationErrorsForTitleAndDescription() throws Exception { String title = TestUtil.createStringWithLength(101); String description = TestUtil.createStringWithLength(501); mockMvc.perform(post("/todo/add") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .param("description", description) .param("title", title) .sessionAttr("todo", new TodoDTO()) ) .andExpect(status().isOk()) .andExpect(view().name("todo/add")) .andExpect(forwardedUrl("/WEB-INF/jsp/todo/add.jsp")) .andExpect(model().attributeHasFieldErrors("todo", "title")) .andExpect(model().attributeHasFieldErrors("todo", "description")) .andExpect(model().attribute("todo", hasProperty("id", nullValue()))) .andExpect(model().attribute("todo", hasProperty("description", is(description)))) .andExpect(model().attribute("todo", hasProperty("title", is(title)))); verifyZeroInteractions(todoServiceMock); } }

 

我们的测试用例调用了 TestUtil 类的 createStringWithLength(int length) 方法。这个方法会按照给定的长度创建并返回字符串。

TestUtil 类的源代码如下:

import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Iterator; import java.util.Map; import java.util.Set; public class TestUtil { public static String createStringWithLength(int length) { StringBuilder builder = new StringBuilder(); for (int index = 0; index < length; index++) { builder.append("a"); } return builder.toString(); } }

 

测试 2: 校验通过且正常入库时

现在,让我们测试可以正常入库时 Controller 能否正常工作。这个测试可以分以下几步:

创建一个 Todo 对象,它会在 TodoService 接口的 add() 方法被调用时返回。 
配置冒烟对象让它在 add() 方法按给定 TodoDTO 对象为参数调用时返回前面创建的 Todo 对象。 
通过以下几步往 ‘/todo/add’ 地址发送 POST 请求: 
把请求的 Content-Type 设置成 ‘application/x-www-form-urlencoded’。 
把 Todo 对象的 description 和 title 字段当做参数发送请求。 
在 session 中添加一个 TodoDTO 对象。因为我们的 Controller 类上包含一个 @SessionAttributes 注解。 
确认返回的 HTTP 状态码是 302。 
确认返回的视图名称是 ‘redirect:todo/{id}’。 
确认请求被定向到地址 ‘/todo/1’。 
确认 model 中 id 属性值为 ‘1’。 
确认返回信息已正确设置。 
确认冒烟对象的 add() 方法仅被调用过一次而且参数是 TodoDTO 对象。使用 ArgumentCaptor 为使用的参数做一个快照。 
确认冒烟对象的其它方法在测试过程中没被调用过。 
确认 TodoDTO 对象的和字段值是正确的。 
这个单元测试的源代码如下:

import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; 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; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest { private MockMvc mockMvc; @Autowired private TodoService todoServiceMock; //此处添加 WebApplicationContext 字段 //setUp() 方法 @Test public void add_NewTodoEntry_ShouldAddTodoEntryAndRenderViewTodoEntryView() throws Exception { Todo added = new TodoBuilder() .id(1L) .description("description") .title("title") .build(); when(todoServiceMock.add(isA(TodoDTO.class))).thenReturn(added); mockMvc.perform(post("/todo/add") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .param("description", "description") .param("title", "title") .sessionAttr("todo", new TodoDTO()) ) .andExpect(status().isMovedTemporarily()) .andExpect(view().name("redirect:todo/{id}")) .andExpect(redirectedUrl("/todo/1")) .andExpect(model().attribute("id", is("1"))) .andExpect(flash().attribute("feedbackMessage", is("Todo entry: title was added."))); ArgumentCaptor<TodoDTO> formObjectArgument = ArgumentCaptor.forClass(TodoDTO.class); verify(todoServiceMock, times(1)).add(formObjectArgument.capture()); verifyNoMoreInteractions(todoServiceMock); TodoDTO formObject = formObjectArgument.getValue(); assertThat(formObject.getDescription(), is("description")); assertNull(formObject.getId()); assertThat(formObject.getTitle(), is("title")); } }

 

总结

我们现在已经使用 SpringMVC 测试框架写了好几个普通 Controller 的测试用例了。通过这篇指南我们学会了:

如何为被测试 Controller 方法创建请求对象。 
如何为被测试 Controller 方法的返回做断言。 
如何为渲染视图的 Controller 写单元测试。 
如何为处理表单的 Controller 写单元测试。 
本系列指南接下来的部分将会告诉我们如何为 REST API 写单元测试。

转载注明出处:如何为 SpringMVC 编写单元测试:普通 Controller 测试

原文链接:http://lzxz1234.github.io/junit/2014/07/10/Unit-Testing-of-Spring-MVC-Controllers-Normal-Controller/


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM