Unit test Rest Controller in Spring Boot using JUnit

This tutorial focuses on unit testing Rest Services in Spring Boot. In the past, we have focused on using JUnit to unit test the business layer. In this tutorial, we will use a simple case study to show how to unit test Spring Boot’s Rest Service using JUnit.

1. Main category capacity

  • Quickly set up the Restfull Service environment
  • Create a GET request to retrieve user information
  • Create a GET request to retrieve user role information
  • Example Create a POST request to add user role information
  • How do I use PostMan to request Restfull Service
  • Unit test GET requests using JUnit
  • Unit test POST requests using JUnit

2. Tools you will need to prepare

  • JDK 1.8 or later
  • Maven project build tool 3.0 and above
  • IDEA code editor

3. You can get all the sample code for this course at the following address

The project code has been uploaded to the GitHub repository. You can obtain the sample source code at the following address:

Github.com/ramostear/S…

4. Project structure

Here is a screenshot of the project structure we will use in this course.

First we need to provide a usable Rest Controller for our unit tests. The UserController file gives us a Rest Controller that we can test. In the UserController class, we provide methods for two types of request, a GET request and a POST request. We then write unit test cases for both request-style methods.

During the rest of the test, we will use Mockito to simulate a request for UserService and MockMvc to simulate a request for UserController. The goal of unit testing is to make testing as narrow as possible. In this case, we only test the methods in UserController.

5. Initialize the project

We are still using Spring Initializr to initialize the project for this course. You need to configure the following parameters:

Now we need to provide two entity classes: User and Role:

User.java

Role.java

6. Provide available business services

All applications require data storage, and the main focus of this course is to unit test the Rest Controller, so you use an ArrayList to act as a database. In this case, a user can have multiple roles, and a role can be assigned to multiple users. A user has an ID, name, alias, and a list of roles, and a role has an ID, name, and description. In the UserService class, the public methods shown in the figure are provided.

7. Provide GET request methods

In the UserController class, we will provide the following exposed GET request methods:

  • @getMapping (value=”/users”) : Obtains all user information
  • @getMapping (value=”/users/{ID}/roles”) : Obtains information about all roles of the user based on the user ID

The detailed code in the userController.java class is as follows:

package com.ramostear.spring.boot.test.restservice.controller;

import com.ramostear.spring.boot.test.restservice.model.Role;
import com.ramostear.spring.boot.test.restservice.model.User;
import com.ramostear.spring.boot.test.restservice.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class UserController {
    private  final UserService userService;

    @Autowired
    public UserController(UserService userService){
        this.userService = userService;
    }

    @GetMapping(value = "/users")
    public List<User> findAllStudents(a){
        return userService.findAllUsers();
    }

    @GetMapping(value = "/users/{id}/roles")
    public List<Role> findUserRoles(@PathVariable(value = "id")String id){
        returnuserService.findUserAllRoles(id); }}Copy the code

8. Use Postman to test RestController

We will use the Postman tool to request of the above two Rest API, first of all to the Postman address bar enter http://localhost:8080/users for testing, to obtain the response information is as follows:

[{"id": "1001"."name": "ramostear"."alias": "Tan Chao-hong"."roles": [{"id": "1001"."name": "admin"."description": "all permissions for this role."}}]]Copy the code

The following graph shows the actual results of Postman’s test of this API:

9. Write unit tests for RestController

When we need to unit test a Rest Controller, we only want to start SpringMVC related components, not all Web components. We can use the WebMvcTest annotation to address such testing requirements. This annotation will disable automatic configuration of Spring Boot and only enable MVC-related configuration. Here are some of the core annotations in the test case:

  • @RunWith(SpringRunner.class) : SpringRunner is short for SpringJUnit4ClassRunner, which extends the BlockJUnit4ClassRunner class to provide Spring application context information at test time.
  • @WebMvcTest(value=UserController.class,secure = false) : This annotation is used to test a Spring MVC application, and the advantage of using this annotation is that we only need to load the UserController class and unit test the methods in it, without loading any other controllers.
  • MockMvc: MockMvc is the main entry point for testing the Spring MVC application and will provide a mock application context for our tests.
  • MockBean: MockBean basically simulates injecting a Bean object into the Spring application context and making the Bean object accessible in the controller.

Here is the source code for the test case:

package com.ramostear.spring.boot.test.restservice;

import com.ramostear.spring.boot.test.restservice.controller.UserController;
import com.ramostear.spring.boot.test.restservice.model.Role;
import com.ramostear.spring.boot.test.restservice.model.User;
import com.ramostear.spring.boot.test.restservice.service.UserService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.skyscreamer.jsonassert.JSONAssert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@WebMvcTest(value = UserController.class,secure = false)
public class UserControllerTests {
    private static Logger logger = LoggerFactory.getLogger(UserControllerTests.class);
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    public void findAllUsers(a) throws Exception{
        User user = new User();
        user.setId("1001");
        user.setName("ramostear");
        user.setAlias("Tan Chao-hong");

        Role role = new Role();
        role.setId("1001");
        role.setName("admin");
        role.setDescription("all permissions for this role.");
        List<Role> roles = new ArrayList<>();
        roles.add(role);
        user.setRoles(roles);
        List<User> users = new ArrayList<>();
        users.add(user);

        Mockito.when(userService.findAllUsers()).thenReturn(users);
        RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/users");
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        String expected = "[{\" id \ ": \" 1001 \ "and \" name \ ": \" ramostear \ ", \ "alias \" : \ "Tan Chaohong \", \ "roles \" : [{\ "id \" : \ "1001 \" and \ "name \" : \ "admin \", \ "the description \":\"all permissions for this role.\"}]}]";
        logger.info(result.getResponse().getContentAsString());
        JSONAssert.assertEquals(expected,result.getResponse().getContentAsString(),false);
    }

    @Test
    public void findAllUserRoles(a) throws Exception{
        Role role = new Role();
        role.setId("1001");
        role.setName("admin");
        role.setDescription("all permissions for this role.");
        List<Role> roles = new ArrayList<>();
        roles.add(role);
        Mockito.when(userService.findUserAllRoles("1001")).thenReturn(roles);
        RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/users/1001/roles");
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        String expected = "[{\"id\":\"1001\",\"name\":\"admin\",\"description\":\"all permissions for this role.\"}]";
       logger.info(result.getResponse().getContentAsString());
        JSONAssert.assertEquals(expected,result.getResponse().getContentAsString(),false); }}Copy the code

Mockito.when().thenreturn (): used to test whether UserService returns as expected when called

MockMvc.perform().andreturn ():mockMvc is primarily used to execute the request andReturn response data

Let’s execute the above two methods and see the test results:

Both methods pass the test, and the console also outputs the following log information:

The 2019-05-10 05:36:40. 18268-567 the INFO [the main] C.R.S.B.T.R.U serControllerTests: [{"id":"1001","name":"admin","description":"all permissions for this role."}] 2019-05-10 05:36:40.585 INFO 18268 -- [ main] c.r.s.b.t.r.UserControllerTests : [{" id ":" 1001 ", "name" : "ramostear", "alias" : "Tan Chaohong", "roles" : [{" id ":" 1001 ", "name" : "admin", "description" : "all permissions for this role."}]}]Copy the code

10. Add a POST request method

Now we add a method in the Rest Controller to add a new role to the user. When the role is successfully set, it will return a create resource status with status code 201. The code is as follows:

 @PostMapping(value = "/users/{id}")
    public ResponseEntity<Object> setUserRole(@PathVariable(value = "id")String id, @RequestBody Role role){
        userService.addUserRole(id,role);
        return new ResponseEntity<>(role, HttpStatus.CREATED);
    }
Copy the code

Use Postman to request this interface and get the following response information:

{
    "id": "1002"."name": "editor"."description": "content editor"
}
Copy the code

The actual result of the Postman request is shown below:

11. Provide unit test cases for Post methods

In the next test, we will use the MockMvcRequestBuilders. Post () method to simulate the method of adding the user role request, and use the accept () method to set the data format, You also need to assert whether the status value of the request response is CREATED and whether the role information returned is as expected. The Post method test source is as follows:

@Test
    public void addUserRole(a) throws Exception{
        String JSON = "{\"id\":\"1002\",\"name\":\"editor\",\"description\":\"content editor\"}";
        RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/users/1001")
                .accept(MediaType.APPLICATION_JSON).content(JSON)
                .contentType(MediaType.APPLICATION_JSON);
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        MockHttpServletResponse response = result.getResponse();
        Assert.assertEquals(HttpStatus.CREATED.value(),response.getStatus());
        String expected = "{\"id\":\"1002\",\"name\":\"editor\",\"description\":\"content editor\"}";
        logger.info(result.getResponse().getContentAsString());
        JSONAssert.assertEquals(expected,result.getResponse().getContentAsString(),false);
    }
Copy the code

Finally, we execute this test case method and observe the test structure:

As you can see from the figure, the Post method has been successfully tested.

This is the end of today’s lesson sharing. In this lesson, I gave a method for testing Rest Controller, and also used Postman for auxiliary testing. All the tests achieved the expected results.

The original address: www.ramostear.com/articles/ju…