Spring Boot Testing - MockMvc
Use Spring’s @MockMvc to test the controller. Do not start the server at all.
- Spring handles the incoming HTTP request and hands it off to your controller.
- With this approach, the code in the controller will be called in exactly the same way as if it were processing a real HTTP request but without the cost of starting the server.
- Use Spring’s MockMvc and ask for that to be injected for you by using the
@AutoConfigureMockMvc
annotation on the test case. - The full Spring application context is started but without the server.
- MockMvc provides support for Spring MVC testing. It encapsulates all web application beans and makes them available for testing.
package com.example.weblayertestingforspringbootapp;
import static org.hamcrest.Matchers.containsString;
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.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
@SpringBootTest
@AutoConfigureMockMvc
public class TestingWebApplicationTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc
.perform(get("/"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
Verify Response Body
@Test
public void givenGreetURI_whenMockMVC_thenVerifyResponse() {
MvcResult mvcResult = this.mockMvc.perform(get("/greet"))
.andDo(print()).andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Hello World!!!"))
.andReturn();
assertEquals("application/json;charset=UTF-8", mvcResult.getResponse().getContentType());
}
Send GET Request With Path Variable
@Test
public void givenGreetURIWithPathVariable_whenMockMVC_thenResponseOK() {
this.mockMvc
.perform(get("/greetWithPathVariable/{name}", "John"))
.andDo(print()).andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.message").value("Hello World John!!!"));
}
Send GET Request With Query Parameters
@Test
public void givenGreetURIWithQueryParameter_whenMockMVC_thenResponseOK() {
this.mockMvc.perform(get("/greetWithQueryVariable")
.param("name", "John Doe")).andDo(print()).andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.message").value("Hello World John Doe!!!"));
}
Send POST Request
@Test
public void givenGreetURIWithPost_whenMockMVC_thenVerifyResponse() {
this.mockMvc.perform(post("/greetWithPost")).andDo(print())
.andExpect(status().isOk()).andExpect(content()
.contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.message").value("Hello World!!!"));
}
Limitations of MockMvc
MockMvc provides an elegant and easy-to-use API to call web endpoints and to inspect and assert their response at the same time. Despite all its benefits, it has a few limitations.
First of all, it does use a subclass of the DispatcherServlet
to handle test requests. To be more specific, the TestDispatcherServlet
is responsible for calling controllers and performing all the familiar Spring magic.
The MockMvc
class wraps this TestDispatcherServlet
internally. So, every time we send a request using the perform()
method, MockMvc
will use the underlying TestDispatcherServlet
directly. Therefore, no real network connections are made, and consequently, we won’t test the whole network stack while using MockMvc
.
Also, because Spring prepares a fake web application context to mock the HTTP requests and responses, it may not support all the features of a full-blown Spring application.
For example, this mock setup doesn’t support HTTP redirections. This may not seem that significant at first. However, Spring Boot handles some errors by redirecting the current request to the /error
endpoint. So, if we’re using the MockMvc
, we may not be able to test some API failures.
Alternatives
- We can set up a more real application context and then use RestTemplate. See Spring Boot Testing - Integration tests for the Controller
- REST-assured: https://www.baeldung.com/rest-assured-tutorial