1 minute read

Spring provides the @WebMvcTest annotation for testing Spring MVC components, providing only the configuration relevant to the MVC tests and not the full auto-configuration, so that we just have what we need to test the code within the controller only. This annotation will auto configure Spring Security and MockMvc as well, so that the security configurations are included and we can mock the services and repositories we need for the testing.

@ExtendWith(SpringExtension.class)
@WebMvcTest(TopicController.class)
public class TopicControllerTest {

    @Autowired
    MockMvc mockMvc;

    @MockBean
    TopicService topicService;

    @Autowired
    ObjectMapper objectMapper;
  }

A typical unit test on the controller will extend the SpringExtension.class to run the test, with the @WebMvcTest specifying the controller class to test. The MockMvc will be autowired, and the service used by the controller will be injected via the @MockBean annotation. As usually the rest controller will accept and output data in json format, we usually also autowire the ObjectMapper to convert our model class to json and back.

To stub the return value of the service, we use the given and willReturn.

List<Topic> topicList = List.of(
        new Topic("first topic"),
        new Topic("second topic")
);
given(topicService.list()).willReturn(topicList);

And to call the api and test the result, we use the MockMvc to perform the api call, and it will return the result as a ResultActions. We can then chain the ResultActions with the andExpect method with ResultMatcher to test outcome.

mockMvc.perform(get(api))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$.length()").value(2));

The perform method accepts a RequestBuilder as an argument, and we have the list of common http methods available as static methods in MockMvcRequestBuilders to use. The above example uses the get method, another example using the post method is illustrated below.

@Test
public void whenCreateTopic_thenReturn301CreatedAndTopic() throws Exception {
    Topic topic = Topic.builder()
            .topicId(1L)
            .title("topic")
            .build();
    given(topicService.create(any())).willReturn(topic);

    RequestBuilder request = post(api)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(topic));
    mockMvc.perform(request)
            .andExpect(status().isCreated())
            .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
            .andExpectAll(
                    jsonPath("$.topicId").value("1"),
                    jsonPath("$.title").value("topic")
            );
}

The jsonPath ResultMatcher allows us to verify the json results using the JsonPath syntax (illustrated in the README.md).

The example above can be found in my github repo.

This is part of a series illustrating how to build a backend Spring boot application.