This is the second part of my spring-test-mvc tutorial and it describes how we can write integration tests for “normal” controller methods (methods that are not using Ajax or processing form submissions).
During this tutorial, we write integration tests for a simple todo application that provides CRUD functions for todo entries. This tutorial concentrates on three functions that are used to view a list of todo entries, view the information of a single todo entry and delete a single todo entry from the database.
Lets get started, shall we?
Note: This tutorial assumes that we are already familiar with the concepts described in the first part of this tutorial.
Getting The Required Dependencies
We can get the required dependencies with Maven by following these steps:
- Declare the Hamcrest (version 1.3) dependency in our pom.xml file. This ensures that we can use the newest Hamcrest matchers in our tests.
- Exclude the hamcrest-core dependency of JUnit.
- Declare the Spring test (version 3.1.2) dependency in our pom.xml file.
- Exclude the hamcrest-all dependency of spring-test-mvc.
- Declare the Spring Test DBUnit (version 1.0.0) dependency in our pom.xml file.
- Declare DBUnit (version 2.4.8) dependency in pom.xml file.
The dependency declarations of our testing dependencies looks as follows:
<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.10</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test-mvc</artifactId>
<version>1.0.0.M2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-all</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.springtestdbunit</groupId>
<artifactId>spring-test-dbunit</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.4.8</version>
<scope>test</scope>
</dependency>
Crash Course to Spring Test DBUnit
We use the Spring Test DBUnit library to provide an integration between the Spring test framework and the DBUnit database testing library. This section describes how we can configure Spring Test DBUnit and use it in our integration tests.
Configuring Spring Test DBUnit
We can configure the Spring Test DBUnit by following these steps:
- Create an application context configuration class that declares the data source bean that provides database access for Spring Test DBUnit.
- Configure our test case.
These steps are described with more details in following.
Creating an Application Context Configuration Class
We can create an application context configuration class by following these steps:
- Annotate the class with the @Configuration annotation.
- Import the application.properties file by using the @PropertySource annotation.
- Add a field which type is Environment to the configuration class and annotate this field with the @Resource annotation.
- Add the configuration of the data source bean to the configuration class.
The source code of the ExampleApplicationContext class looks as follows:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
@PropertySource("classpath:application.properties")
public class ExampleApplicationContext {
@Resource
private Environment environment;
@Bean
public DataSource dataSource() {
BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass(environment.getRequiredProperty("db.driver"));
dataSource.setJdbcUrl(environment.getRequiredProperty("db.url"));
dataSource.setUsername(environment.getRequiredProperty("db.username"));
dataSource.setPassword(environment.getRequiredProperty("db.password"));
return dataSource;
}
}
Configuring Our Integration Test
We can configure our integration test by following these steps:
- Configure the used test runner by annotation the test class with the @RunWith annotation. The correct test runner class is the SpringJUnit4ClassRunner.
- Annotate the test class with the @ContextConfiguration annotation and provide the type of our application context configuration class as its value.
- Configure the required test execution listeners by annotating the test class with the @TestExecutionListeners annotation. and provide the DbUnitTestExecutionListener and the standard Spring listeners as its value. The DBUnitTestExecution listener ensures that Spring process the DBUnit annotations that are used to configure the used data sets.
- Add a DataSource field to the test class and annotate the field with the @Resource annotation.
The source code of a test class that uses Spring Test DBUnit is given in following:
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import javax.annotation.Resource;
import javax.sql.DataSource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
public class Test {
@Resource
private DataSource datasource;
//Add test methods here
}
Using Spring Test DBUnit
The homepage of the Spring Test DBUnit project describes how we can use annotations to initalize the database to a known state before our run, reset the database tables after our test has been completed and verify the contents of the database once our test is finished. During this tutorial we use two annotations that are described in following:
- The @DatabaseSetup annotation is used to initialize the database to a known state before a test is run.
- The @ExpectedDatabase annotation is used to verify the contents of the used database after a test is finished.
Crash Course to spring-test-mvc
We can write an integration test with spring-test-mvc by following these steps:
- Create the executed request and execute it.
- Verify that the response is correct.
Both of these steps are described with more details in the following subsections.
Creating And Executing Requests
We can create the executed request by using the perform(RequestBuilder requestBuilder) method of the MockMvc class. The MockMvcRequestBuilders class provides static methods that we can use to create the actual request builders. These methods are described in the following:
- get() method creates a request builder for GET request.
- delete() method creates a request builder for DELETE request.
- fileUpload() creates a request builder for multipart request.
- post() method creates a request builder for POST request.
- put() method creates a request builder for PUT method.
We can get more details about building the executed requests by taking a look at the MockHttpServletRequestBuilder class.
Verifying The Response
The ResultActions interface declares methods that we can use to apply actions to the result of an executed requests. These methods are described in the following:
- void andExpect(ResultMatcher matcher) method is used to specify assertions to the result of the executed query.
- void andDo(ResultHandler handler) method is used to apply an action to the result of the request.
- MvcResult andReturn() method returns the result of the request.
We can get more information about the actions that we can apply to the result of the executed requests by taking a look at the following classes:
- The MockMvcResultMatchers class is used to specify assertions to the result of the request.
- The MockMvcResultHandlers class for finding out out what kind of actions we can perform to the result of the executed request.
Writing Integration Tests for Controllers
We are now ready to write integration tests for our application. Lets start by taking a quick look at the anatomy of our todo application.
The Anatomy of Our Todo Application
This section describes the common parts of our example application and its goal is to help us to understand the rest of this blog entry. To be more specific, we will take a closer look at the domain model, the service interface and the controller.
The Domain Model
The domain model of our example application consists of a single entity called Todo and its looks as follows:
import org.joda.time.DateTime;
import javax.persistence.*;
@Entity
@Table(name="todos")
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "creation_time", nullable = false)
@Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime creationTime;
@Column(name = "description", nullable = true, length = 500)
private String description;
@Column(name = "modification_time", nullable = false)
@Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime modificationTime;
@Column(name = "title", nullable = false, length = 100)
private String title;
@Version
private long version;
public Todo() {
}
//Getters and other methods
}
The Service Interface
In order to understand the implementation of our controller methods, we must understand the contract between our controller class and the service layer. This contract is described by the TodoService interface. This interface declares the following methods:
- Todo deleteById(Long id) method deletes a single todo entry and returns the deleted entry. If the deleted todo entry is not found, this method throws TodoNotFoundException.
- List<Todo> findAll() method returns a list of todo entries. If no todo entries is found, this method returns an empty list.
- Todo findById(Long id) returns a todo entry by using the given id as a search criteria. If no todo entry is found, this method throws TodoNotFoundException.
The source code of the TodoService interface looks as follows:
public Todo deleteById(Long id) throws TodoNotFoundException;
public List<Todo> findAll();
public Todo findById(Long id) throws TodoNotFoundException;
}
The Controller
The name of our controller class is TodoController. This class provides controller methods that can be used to view a todo list page, view the information of a single todo entry and delete a single todo entry. The source code of the TodoController class looks as follows:
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.annotation.Resource;
import javax.validation.Valid;
@Controller
public class TodoController {
@Resource
private TodoService service;
@Resource
private MessageSource messageSource;
@RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.GET)
public String deleteById(@PathVariable("id") Long id, RedirectAttributes attributes) throws TodoNotFoundException {
Todo deleted = service.deleteById(id);
addFeedbackMessage(attributes, "feedback.message.todo.deleted", deleted.getTitle());
return createRedirectViewPath("/");
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public String findAll(Model model) {
List<Todo> models = service.findAll();
model.addAttribute("todos", models);
return "todo/list";
}
@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";
}
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();
}
}
Creating The Integration Test Skeleton Class
We can now combine the lessons learned from the first part of this tutorial and this blog entry, and create a skeleton class for our integration tests. We can do this by following these steps:
- Configure spring-test-mvc by using the technique described in the first part of this tutorial.
- Configure Spring Test DBUnit using the technique that was explained earlier in this blog entry.
- Configure the DBUnit databaset that is used to initialize our database to a known state before our tests are run by using the @DatabaseSetup annotation.
The relevant parts of the ITTodoControllerTest class looks as follows:
import com.github.springtestdbunit.annotation.DatabaseSetup;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.web.server.MockMvc;
import org.springframework.test.web.server.samples.context.WebContextLoader;
import org.springframework.test.web.server.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import javax.annotation.Resource;
import javax.sql.DataSource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
@Resource
private DataSource datasource;
@Resource
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webApplicationContextSetup(webApplicationContext)
.build();
}
//Add tests here
}
The name of our DBUnit dataset file is todoData.xml and its content looks as follows:
<todos id="1" creation_time="2012-10-21 11:13:28" description="Lorem ipsum" modification_time="2012-10-21 11:13:28" title="Foo" version="0"/>
<todos id="2" creation_time="2012-10-21 11:13:28" description="Lorem ipsum" modification_time="2012-10-21 11:13:28" title="Bar" version="0"/>
</dataset>
Writing Integration Tests for Controller Methods
We are now finally ready to write integration tests for our controller methods. The steps required to write integration tests for each controller method are described with more details in following.
View Todo List
The controller method that is used to view the todo list is called findAll(). We can write an integration test for this method by following these steps:
- Use @ExpectedDatabase annotation to verify that no changes are made to the database.
- Perform a GET request to url ‘/’.
- Verify that the HTTP status code is 200.
- Verify that name of the rendered view is ‘todo/list’.
- Verify that the request is forwarded to url ‘/WEB-INF/jsp/todo/list.jsp’.
- Verify that the size of the todo list is 2.
- Verify that the todo list contains the correct items.
The source code of our test case looks as follows:
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.web.server.MockMvc;
import org.springframework.test.web.server.samples.context.WebContextLoader;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
//Add data source and web application context here
private MockMvc mockMvc;
//Add setUp() method here
@Test
@ExpectedDatabase("toDoData.xml")
public void findAll() throws Exception {
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"))
)
)));
}
}
View Todo Entry
The findById() method of the TodoController class is used to view the information of a single todo entry. We have to write two integration tests for this function:
- We have to ensure that the information of the todo entry is shown if a todo entry is found.
- We have to ensure that the 404 page is shown if no todo entry is found.
We can write the first integration test by following these steps:
- Use the @ExcectedDatabase annotation to ensure that no changes are made to the database.
- Perform a GET request to url ‘/todo/1′.
- Verify that the HTTP status code is 200.
- Verify that the name of the rendered view is ‘todo/view’.
- Verify that the request is forwarded to url ‘/WEB-INF/jsp/todo/view.jsp’.
- Verify that the model contains the information of the found todo entry.
The source code of the first integration test looks as follows:
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.web.server.MockMvc;
import org.springframework.test.web.server.samples.context.WebContextLoader;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
//Add data source and web application context here
private MockMvc mockMvc;
//Add setUp() method here
@Test
@ExpectedDatabase("toDoData.xml")
public void findById() throws Exception {
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"))));
}
}
We can write the second integration test by following these steps:
- Use the @ExpectedDatabase annotation to verify that no changes are made to the database.
- Perform a GET request to url ‘/todo/3′.
- Verify that the HTTP status code is 404.
- Verify that the name of the view is ‘error/404′.
- Verify that the request is forwarded to url ‘/WEB-INF/jsp/error/404.jsp’.
The source code of the second integration test looks as follows:
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.web.server.MockMvc;
import org.springframework.test.web.server.samples.context.WebContextLoader;
import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
//Add data source and web application context here
private MockMvc mockMvc;
//Add setUp() method here
@Test
@ExpectedDatabase("toDoData.xml")
public void findByIdWhenTodoIsNotFound() throws Exception {
mockMvc.perform(get("/todo/{id}", 3L))
.andExpect(status().isNotFound())
.andExpect(view().name("error/404"))
.andExpect(forwardedUrl("/WEB-INF/jsp/error/404.jsp"));
}
}
Delete Todo Entry
The deleteById() method of the TodoController class is used to delete a todo entry from the database. We have to write two integration tests for it:
- We have to ensure that the found todo entry is deleted.
- We have to ensure that if no todo entry is found, a 404 page is shown.
We can write the first integration test by following these steps:
- Use the @ExpectedDatabase annotation to specify the DBUnit dataset that is used to verify that the todo entry has been deleted from the database.
- Perform a GET request to url ‘/todo/delete/1′.
- Verify that the HTTP status code is 200.
- Verify that name of the view is ‘redirect:/’.
- Verify that the correct feedback message is given as a flash attribute.
The source code of the first integration test looks as follows:
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.web.server.MockMvc;
import org.springframework.test.web.server.samples.context.WebContextLoader;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
//Add data source and web application context here
private MockMvc mockMvc;
//Add setUp() method here
@Test
@ExpectedDatabase("todoData-delete-expected.xml")
public void deleteById() throws Exception {
mockMvc.perform(get("/todo/delete/{id}", 1L))
.andExpect(status().isOk())
.andExpect(view().name("redirect:/"))
.andExpect(flash().attribute("feedbackMessage", is("Todo entry: Foo was deleted.")));
}
}
The content of the todoData-delete-expected.xml file looks as follows:
<todos id="2" creation_time="2012-10-21 11:13:28" description="Lorem ipsum" modification_time="2012-10-21 11:13:28" title="Bar" version="0"/>
</dataset>
We can write the second integration test by following these steps:
- Use the @ExpectedDatabase annotation to specify that no changes are made to the database.
- Perform a GET request to url ‘/todo/delete/3′
- Verify that the HTTP status code is 404.
- Verify that the name of the rendered view is ‘error/404′.
- Verify that the request is forwarded to url ‘/WEB-INF/jsp/error/404.jsp’.
The source code of the second integration test looks as follows:
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.github.springtestdbunit.annotation.ExpectedDatabase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.test.web.server.MockMvc;
import org.springframework.test.web.server.samples.context.WebContextLoader;
import static org.springframework.test.web.server.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = WebContextLoader.class, classes = {ExampleApplicationContext.class})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@DatabaseSetup("toDoData.xml")
public class ITTodoControllerTest {
//Add data source and web application context here
private MockMvc mockMvc;
//Add setUp() method here
@Test
@ExpectedDatabase("toDoData.xml")
public void deleteByIdWhenTodoIsNotFound() throws Exception {
mockMvc.perform(get("/todo/delete/{id}", 3L))
.andExpect(status().isNotFound())
.andExpect(view().name("error/404"))
.andExpect(forwardedUrl("/WEB-INF/jsp/error/404.jsp"));
}
}
Conclusion
We have now learned how we can write integration tests for controller methods that do not process form submissions or use Ajax. This tutorial has taught us three things:
- It is really easy to execute requests and specify assertions to the response of the executed request by using spring-test-mvc.
- The integration tests written by using spring-test-mvc are very readable. Thus, they are an excellent way to document the functions of our application.
- We cannot use spring-test-mvc to verify that the view is working properly but we can verify that the right view is rendered.
In the next part of this tutorial, we learn to write integration tests for controller methods that processes form submissions. In the meantime, we can get the example application of this blog entry from Github.

