Spring Boot MockMvc Example with @WebMvcTest

Learn to use Spring MockMvc to perform integration testing of REST controllers. The Spring MockMvc class is part of the Spring test framework and helps in testing the controllers by explicitly starting a Servlet container.

In this Spring Boot MockMvc tutorial, we will use MockMvc along with Spring’s @WebMvcTest annotation to execute JUnit tests for REST controller handler methods written for the Spring Boot HATEOAS example.

1. Maven

The spring-boot-starter-test dependency includes all required dependencies to create and execute tests.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
</dependency>

If not using spring boot then include the following dependencies. we can also use JUnit 5 dependencies.

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>{version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>{version}</version>
    <scope>test</scope>
</dependency>

2. Unit Test Structure

A JUnit test class to test the Spring MVC controller request and responses can use the below-given configuration.

@WebMvcTest(EmployeeRESTController.class)
public class TestEmployeeRESTController {

    @Autowired
    private MockMvc mvc;

    // Your test methods would go here
    // ...
}
  • The @WebMvcTest annotation is used for Spring MVC tests. It disables full auto-configuration and instead applies only configuration relevant to MVC tests.
  • The @WebMvcTest annotation auto-configure MockMvc instance as well.
  • Using EmployeeRESTController.class as the parameter, we are asking to initialize only one web controller, and we need to provide the remaining dependencies required using Mock objects.

3. Spring Boot MockMvc Example

Let’s create some JUnit tests that will test different HTTP methods in the controller class.

3.1. HTTP GET API

The HTTP APIs defined in the controller are given below. In the given tests, we are testing two GET APIs – one without a path parameter and another with a path parameter.

@GetMapping(value = "/employees")
public EmployeeListVO getAllEmployees()
{
    //code
}
 
@GetMapping(value = "/employees/{id}") 
public ResponseEntity<EmployeeVO> getEmployeeById (@PathVariable("id") int id)
{
    //code
}

And corresponding tests for the methods are given below. These tests hit the APIs, pass the path parameters using MockMvcRequestBuilders and verify the status response codes and response content using MockMvcResultMatchers and MockMvcResultHandlers.

@Autowired
private MockMvc mvc;
 
@Test
public void getAllEmployeesAPI() throws Exception 
{
  mvc.perform(MockMvcRequestBuilders
  			.get("/employees")
  			.accept(MediaType.APPLICATION_JSON))
      .andDo(print())
      .andExpect(status().isOk())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employees").exists())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employees[*].employeeId").isNotEmpty());
}
 
@Test
public void getEmployeeByIdAPI() throws Exception 
{
  mvc.perform( MockMvcRequestBuilders
	      .get("/employees/{id}", 1)
	      .accept(MediaType.APPLICATION_JSON))
      .andDo(print())
      .andExpect(status().isOk())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employeeId").value(1));
}

3.2. HTTP POST API

The HTTP POST API is defined in the controller as:

@PostMapping(value = "/employees")
public ResponseEntity<EmployeeVO> addEmployee (@Valid @RequestBody EmployeeVO employee)
{
    //code
    return new ResponseEntity<EmployeeVO>(employee, HttpStatus.CREATED);
}

And corresponding mockmvc test for post JSON request is as follows:

@Autowired
private MockMvc mvc;
 
@Test
public void createEmployeeAPI() throws Exception 
{
  mvc.perform( MockMvcRequestBuilders
	      .post("/employees")
	      .content(asJsonString(new EmployeeVO(null, "firstName4", "lastName4", "email4@mail.com")))
	      .contentType(MediaType.APPLICATION_JSON)
	      .accept(MediaType.APPLICATION_JSON))
      .andExpect(status().isCreated())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employeeId").exists());
}
 
public static String asJsonString(final Object obj) {
    try {
        return new ObjectMapper().writeValueAsString(obj);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

3.3. HTTP PUT API

The HTTP API is defined in the controller as:

@PutMapping(value = "/employees/{id}")
public ResponseEntity<EmployeeVO> updateEmployee (@PathVariable("id") int id, @Valid @RequestBody EmployeeVO employee)
{
    //code
    return new ResponseEntity<EmployeeVO>(emp, HttpStatus.OK);
}

And corresponding tests for the methods are:

@Test
public void updateEmployeeAPI() throws Exception 
{
  mvc.perform( MockMvcRequestBuilders
	      .put("/employees/{id}", 2)
	      .content(asJsonString(new EmployeeVO(2, "firstName2", "lastName2", "email2@mail.com")))
	      .contentType(MediaType.APPLICATION_JSON)
	      .accept(MediaType.APPLICATION_JSON))
      .andExpect(status().isOk())
      .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("firstName2"))
      .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("lastName2"))
      .andExpect(MockMvcResultMatchers.jsonPath("$.email").value("email2@mail.com"));
}

3.4. HTTP DELETE API

The HTTP API is defined in the controller as:

@DeleteMapping(value = "/employees/{id}")
public ResponseEntity<HttpStatus> removeEmployee (@PathVariable("id") int id)
{
    //code
    return new ResponseEntity<HttpStatus>(HttpStatus.ACCEPTED);
}

And corresponding tests for the methods are:

@Test
public void deleteEmployeeAPI() throws Exception 
{
  mvc.perform( MockMvcRequestBuilders.delete("/employees/{id}", 1) )
        .andExpect(status().isAccepted());
}

3.5. Test Results

When we run the above tests, we get the test results below.

Spring Boot MockMvc Example
Test Results

4. Conclusion

In this spring boot integration test example, we learned to write Spring MVC integration tests using MockMvc class. We learned to write JUNit tests for HTTP GET, POST, PUT and DELETE APIs.

We also looked to verify API response status and response body, pass HTTP headers, and request path parameters as well.

Happy Learning !!

Comments

Subscribe
Notify of
guest
10 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.