Spring Boot REST Controller JUnit Test Example

Unit tests are used to test the smaller units of an application. Unit tests make sure that a unit of code is working as expected. There are many unit testing frameworks available in Java. Example: TestNG, JUnit, Mockito, etc. With these frameworks, we can easily add spring boot controller JUnit test cases.

In this article, we will learn how to write JUnit test cases for Spring boot REST APIs. We will use JUnit 5 and Mockito to write the unit test cases.

Technologies used in this article are:

  • Spring Boot version : 2.3.1.BUILD-SNAPSHOT
  • Java version 1.8
  • JUnit 5

Table of Contents

Create a Spring boot application

Create a Spring Boot application with required dependency. We need spring-boot-starter-web dependency for supporting REST API creation and spring-boot-starter-test dependency for adding test framework libraries to the application.

Since we are writing JUnit 5 test cases, junit-vintage-engine has been excluded(used for running JUnit 4 test cases).

<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>
        <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Create REST endpoints

We will create simple CRUD endpoints for the Student DTO class. We will create a RestController class, a service class, and a DTO class.

Student DTO class

Let us create a DTO class with the name Student.java

package com.asbnotebook.dto;

public class Student {
    private Integer id;
    private String name;
    //getters and setters
}

RestController class

Create a RestController class with the name StudentController.java

This class will have CRUD REST endpoints for Student DTO.

The class uses the StudentService service class to perform the CRUD operation.

package com.asbnotebook.controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.asbnotebook.dto.Student;
import com.asbnotebook.service.StudentService;

@RestController
public class StudentController {

    @Autowired
    private StudentService studentService;
    
    @GetMapping("/getMapping")
    public ResponseEntity<List<Student>> getStudents() {
        List<Student> students = studentService.getStudents();
        return new ResponseEntity<>(students, HttpStatus.OK);
    }

    @PostMapping("/postMapping")
    public ResponseEntity<Student> saveStudent(@RequestBody Student student) {
        student = studentService.saveStudent(student);
        return new ResponseEntity<>(student, HttpStatus.CREATED);
    }

    @PutMapping("/putMapping")
    public ResponseEntity<Student> putExample(@RequestBody Student student) {
        student = studentService.updateStudent(student);
        return new ResponseEntity<>(student, HttpStatus.OK);
    }

    @DeleteMapping("/deleteMapping")
    public ResponseEntity<String> deleteExample(@RequestParam("student-id") String studentId) {
        String response = studentService.deleteStudent(studentId);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }
}

Student Service class

Create a StudentService.java service class. This class provides the required functionalities to the controller layer.

package com.asbnotebook.service;

import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.asbnotebook.dto.Student;

@Service
public class StudentService {

    public List<Student> getStudents() {
        List<Student> students = new ArrayList<>();
        Student student = new Student();
        students.add(student);
        return students;
    }

    public Student saveStudent(Student student) {
        student.setId(1);
        student.setName("Arun");
        return student;
    }

    public Student updateStudent(Student student) {
        student.setId(2);
        student.setName("John");
        return student;
    }

    public String deleteStudent(String studentId) {
        return "Student is deleted";
    }
}

Writing the RestController Unit Tests

Create a JUnit test class with the name StudentControllerTest.java under the /src/test directory. Add the code given below.

package com.asbnotebook;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.List;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
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.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import com.asbnotebook.dto.Student;
import com.asbnotebook.service.StudentService;
import com.fasterxml.jackson.databind.ObjectMapper;

@WebMvcTest
public class StudentControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private StudentService studentService;

    private static ObjectMapper mapper = new ObjectMapper();

    @Test
    public void testGetExample() throws Exception {
        List<Student> students = new ArrayList<>();
        Student student = new Student();
        student.setId(1);
        student.setName("Arun");
        students.add(student);
        Mockito.when(studentService.getStudents()).thenReturn(students);
        mockMvc.perform(get("/getMapping")).andExpect(status().isOk()).andExpect(jsonPath("$", Matchers.hasSize(1)))
                .andExpect(jsonPath("$[0].name", Matchers.equalTo("Arun")));
    }

    @Test
    public void testPostExample() throws Exception {
        Student student = new Student();
        student.setId(1);
        student.setName("Arun");
        Mockito.when(studentService.saveStudent(ArgumentMatchers.any())).thenReturn(student);
        String json = mapper.writeValueAsString(student);
        mockMvc.perform(post("/postMapping").contentType(MediaType.APPLICATION_JSON).characterEncoding("utf-8")
                .content(json).accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", Matchers.equalTo(1)))
                .andExpect(jsonPath("$.name", Matchers.equalTo("Arun")));
    }

    @Test
    public void testPutExample() throws Exception {
        Student student = new Student();
        student.setId(2);
        student.setName("John");
        Mockito.when(studentService.updateStudent(ArgumentMatchers.any())).thenReturn(student);
        String json = mapper.writeValueAsString(student);
        mockMvc.perform(put("/putMapping").contentType(MediaType.APPLICATION_JSON).characterEncoding("utf-8")
                .content(json).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
                .andExpect(jsonPath("$.id", Matchers.equalTo(2)))
                .andExpect(jsonPath("$.name", Matchers.equalTo("John")));
    }

    @Test
    public void testDeleteExample() throws Exception {
        Mockito.when(studentService.deleteStudent(ArgumentMatchers.anyString())).thenReturn("Student is deleted");
        MvcResult requestResult = mockMvc.perform(delete("/deleteMapping").param("student-id", "1"))
                .andExpect(status().isOk()).andExpect(status().isOk()).andReturn();
        String result = requestResult.getResponse().getContentAsString();
        assertEquals(result, "Student is deleted");
    }
}

Few of the points to notice here are:

  • @WebMvcTest: This annotation initializes web MVC related configurations required to write the JUnit test case for controller classes.
  • MockMvc: This class provides the required methods to test the Spring MVC layer. with perform() method, we can test different HTTP endpoints(GET, POST, PUT, DELETE, etc)
  • @MockBean: This annotation creates mocked beans in the spring application context.
  • @Test: Indicated that the method is a test case.
  • Mockito: This class of Mockito framework creates a mock of an object. We have mocked the return values of the service layer in our example.
  • jsonpath: Spring boot provides built-in supports JsonPath that is helpful to verify the JSON response.
  • MvcResult: MockMvc returns a result object on calling andReturn(), that contains the response details of a particular MVC operation.

Run the Unit tests

Now we can run our JUnit test cases. With IDE like STS/Eclipse, we can run the test case by Right click on Project > Run AS > JUnit.

If every test case runs successfully, we get JUnit output similar to the below image.

spring boot rest junit test case example

Conclusion

In this article, we learned how to write Unit test cases for Spring boot REST APIs using the JUnit 5 and Mockito.

The complete example code is available on Github. Happy coding 🙂

Spring Boot REST Controller JUnit Test Example
Scroll to top

Discover more from ASB Notebook

Subscribe now to keep reading and get access to the full archive.

Continue reading