Spring rest controller unit test example

Learn to unit test given Spring rest controller APIs using Junit 5 and mockito. This technique can be applied to spring boot as well as spring MVC applications, both.

1. How to write correct unit test for rest controllers

While writing junit test for a rest controller method, we shall keep in mind that:

  • A unit test is supposed to test only a certain part of code (i.e. code written in controller class), so we shall mock all the dependencies injected and used in controller class.
  • If the test utilizes other dependencies (e.g. database/network) then it is integration testing and not unit testing.
  • We should not use any webserver otherwise it will make the unit testing slow.
  • Each unit test should be independent of other tests.
  • By definition, unit tests should be fast.

2. Unit test controllers using Junit 5 and Mockito

2.1. Maven dependencies

Start by including the required dependencies. We are using the Spring boot application here.

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

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

    <!-- exclude junit 4 -->

    <exclusions>
        <exclusion>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- Junit 5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <scope>test</scope>
</dependency>

<!-- Mockito extention -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>

2.2. REST Controller

Here is the Spring boot rest controller, we will be writing unit tests for.

  • The controller has dependency on EmployeeDAO class for persistence.
  • addEmployee() api need access to the request context using ServletUriComponentsBuilder.
  • addEmployee() api returns HTTP status and header using ResponseEntity class.
import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import com.howtodoinjava.rest.dao.EmployeeDAO;
import com.howtodoinjava.rest.model.Employee;
import com.howtodoinjava.rest.model.Employees;

@RestController
@RequestMapping(path = "/employees")
public class EmployeeController 
{
    @Autowired
    private EmployeeDAO employeeDao;

    @GetMapping(path="/", produces = "application/json")
    public Employees getEmployees() 
    {
        return employeeDao.getAllEmployees();
    }
    
    @PostMapping(path= "/", consumes = "application/json", produces = "application/json")
    public ResponseEntity<Object> addEmployee(@RequestBody Employee employee) {       
                
        //add resource
        employeeDao.addEmployee(employee);
        
        //Create resource location
        URI location = ServletUriComponentsBuilder.fromCurrentRequest()
                                    .path("/{id}")
                                    .buildAndExpand(employee.getId())
                                    .toUri();
        
        //Send location in response
        return ResponseEntity.created(location).build();
    }
}

2.3. Unit tests

The test class given below contains unit tests for the spring boot rest controller mentioned above. This test class:

  • uses @Mock annotation to created mock object for EmployeeDAO dependency.
  • uses @InjectMocks to create EmployeeController class and also inject the mocked employeeDAO instance.
  • MockitoExtension initializes mocks and handles strict stubbings. This extension is the JUnit Jupiter equivalent of our JUnit4 MockitoJUnitRunner.
  • Using JUnitPlatform is optional. It allows junit 5 tests to be run with IDEs and build systems that support JUnit 4 but do not yet support the JUnit Platform directly.
  • MockHttpServletRequest and RequestContextHolder supply the request context where code under test needs it.
  • Use org.mockito.Mockito.when() and thenReturn() apis to mock the desired behavior.
  • Finally use junit 5 assertions to assert the test results with expected results.

Read More : Mockito annotations – @Mock, @Spy, @Captor, @InjectMocks

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.howtodoinjava.rest.controller.EmployeeController;
import com.howtodoinjava.rest.dao.EmployeeDAO;
import com.howtodoinjava.rest.model.Employee;
import com.howtodoinjava.rest.model.Employees;

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
public class EmployeeControllerTest 
{
    @InjectMocks
    EmployeeController employeeController;
    
    @Mock
    EmployeeDAO employeeDAO;
    
    @Test
    public void testAddEmployee() 
    {
        MockHttpServletRequest request = new MockHttpServletRequest();
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
        
        when(employeeDAO.addEmployee(any(Employee.class))).thenReturn(true);
        
        Employee employee = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
        ResponseEntity<Object> responseEntity = employeeController.addEmployee(employee);
        
        assertThat(responseEntity.getStatusCodeValue()).isEqualTo(201);
        assertThat(responseEntity.getHeaders().getLocation().getPath()).isEqualTo("/1");
    }
    
    @Test
    public void testFindAll() 
    {
        // given
        Employee employee1 = new Employee(1, "Lokesh", "Gupta", "howtodoinjava@gmail.com");
        Employee employee2 = new Employee(2, "Alex", "Gussin", "example@gmail.com");
        Employees employees = new Employees();
        employees.setEmployeeList(Arrays.asList(employee1, employee2));

        when(employeeDAO.getAllEmployees()).thenReturn(employees);

        // when
        Employees result = employeeController.getEmployees();

        // then
        assertThat(result.getEmployeeList().size()).isEqualTo(2);
        
        assertThat(result.getEmployeeList().get(0).getFirstName())
                        .isEqualTo(employee1.getFirstName());
        
        assertThat(result.getEmployeeList().get(1).getFirstName())
                        .isEqualTo(employee2.getFirstName());
    }
}

3. Demo

Run the above tests within IDE. I have used Eclipse.

Spring rest controller unit test example
Spring rest controller unit test example

4. Conclusion

In this spring boot rest controller unit testing example with Junit 5 and mockito, we learned to write tests that mock all the controller dependencies and only test the necessary part.

We also learned that we shall not use actual webserver to run the application while unit testing. The server will be needed while integration testing only.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

3 thoughts on “Spring rest controller unit test example”

  1. If you guys are using it past 2019 in the current spring boot version you can skip those dependencies and annotated your test classes with @SpringBootTest.

    Thanks for the article it saved me !!!

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.