Test mvc controller java

Test a Spring Boot REST Controller with JUnit 5

Learn to unit test given Spring Boot REST controller using Junit 5, Mockito and MockMvc autoconfigured using @WebMvcTest. This technique can be applied to Spring boot as well as Spring MVC applications.

Start by including the latest version of spring-boot-starter-test starter dependency.

 org.springframework.boot spring-boot-starter-test test 

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

  • The controller has a dependency on EmployeeDAO class for persistence.
  • addEmployee() api needs access to the request context using ServletUriComponentsBuilder .
  • addEmployee() api returns HTTP status and header using ResponseEntity class.
@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 addEmployee(@RequestBody Employee employee) < employeeDao.addEmployee(employee); URI location = ServletUriComponentsBuilder.fromCurrentRequest() .path("/") .buildAndExpand(employee.getId()) .toUri(); return ResponseEntity.created(location).build(); > >

2. Unit Testing using Spring Boot @WebMvcTest

The @WebMvcTest annotation is used to unit test the Spring MVC components (@Controller, @ControllerAdvice). It disables the full autoconfiguration and only configures the Spring Security and MockMvc .

@WebMvcTest(EmployeeRESTController.class) public class TestEmployeeRESTController

Finally, use MockMvc bean instance to invoke the APIs and verify the results.

@Test public void getAllEmployeesAPI() throws Exception < mvc.perform(MockMvcRequestBuilders .get("/employees") .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.employees").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$.employees[*].employeeId").isNotEmpty()); >@Test public void createEmployeeAPI() throws Exception < mvc.perform( MockMvcRequestBuilders .post("/employees") .content(asJsonString(new EmployeeVO(null, "firstName", "lastName", "admin@mail.com"))) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(MockMvcResultMatchers.jsonPath("$.employeeId").exists()); >public static String asJsonString(final Object obj) < try < return new ObjectMapper().writeValueAsString(obj); >catch (Exception e) < throw new RuntimeException(e); >>

3. Unit Testing Spring Controller using Mockito

To use Mockito with Spring, include the following dependency:

  org.mockito mockito-junit-jupiter test 

The test class contains unit tests for the spring boot rest controller using the Mockito APIs. The 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.
  • 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.
import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import com.howtodoinjava.rest.controller.EmployeeController; import com.howtodoinjava.rest.dao.EmployeeRepository; import com.howtodoinjava.rest.model.Employee; import com.howtodoinjava.rest.model.Employees; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; 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; @ExtendWith(MockitoExtension.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"); ResponseEntityresponseEntity = employeeController.addEmployee(employeeToAdd); assertThat(responseEntity.getStatusCodeValue()).isEqualTo(201); assertThat(responseEntity.getHeaders().getLocation().getPath()).isEqualTo("/1"); > @Test public void testFindAll() < 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); Employees result = employeeController.getEmployees(); assertThat(result.getEmployeeList().size()).isEqualTo(2); assertThat(result.getEmployeeList().get(0).getFirstName()).isEqualTo(employee1.getFirstName()); assertThat(result.getEmployeeList().get(1).getFirstName()).isEqualTo(employee2.getFirstName()); >>

While writing a 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 the controller class), so we shall mock all the dependencies injected and used in the controller class.
  • If the test utilizes outer dependencies (e.g., database/network), then it is integration testing, not unit testing.
  • We should not use any web server; otherwise, it will slow down unit testing.
  • Each unit test should be independent of other tests.
  • By definition, unit tests should be fast.
Читайте также:  Check browser with php

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.

Источник

Модульное тестирование контроллеров Spring MVC: REST API

Spring MVC предоставляет простой способ создания REST API. Однако написание комплексных и быстрых модульных тестов для этих API было проблематичным. Выпуск Spring MVC Test Framework дал нам возможность писать модульные тесты, которые читабельны, всеобъемлющи и быстры.

В этой записи блога описывается, как мы можем написать модульные тесты для REST API, используя среду Spring MVC Test. В этом посте мы напишем модульные тесты для методов контроллера, которые предоставляют функции CRUD для записей todo.

Получение необходимых зависимостей с Maven

Мы можем получить необходимые тестовые зависимости, добавив следующие объявления зависимостей в наш POM-файл:

  • Hamcrest 1.3 ( Хамкрест-все ). Мы используем совпадения Hamcrest, когда пишем утверждения для ответов.
  • Junit 4.11. Нам нужно исключить зависимость от hamcrest-core, потому что мы уже добавили зависимость hamcrest-all .
  • Мокито 1.9.5 ( ядро мокито ). Мы используем Mockito в качестве нашей библиотеки для насмешек.
  • Весенний тест 3.2.3. РЕЛИЗ
  • JsonPath 0.8.1 ( json-path и json-path-assert ). Мы используем JsonPath, когда пишем утверждения для документов JSON, возвращаемых нашим REST API.

Соответствующие объявления зависимостей выглядят следующим образом:

Давайте продолжим и поговорим немного о конфигурации наших модульных тестов.

Настройка наших модульных тестов

Модульные тесты, которые мы напишем в этом посте, используют конфигурацию на основе контекста веб-приложения. Это означает, что мы конфигурируем инфраструктуру Spring MVC с помощью класса конфигурации контекста приложения или файла конфигурации XML.

Читайте также:  Python pandas read csv column

Поскольку в первой части этого руководства описаны принципы, которым мы должны следовать при настройке контекста приложения для нашего приложения, эта проблема не обсуждается в этом сообщении в блоге.

Тем не менее, есть одна вещь, которую мы должны рассмотреть здесь.

Класс (или файл) настройки контекста приложения, который настраивает веб-уровень нашего примера приложения, не создает компонент разрешения исключений. Класс SimpleMappingExceptionResolver, используемый в предыдущих частях этого учебника, отображает имя класса исключения в представление, которое отображается при создании настроенного исключения.

Это имеет смысл, если мы реализуем «нормальное» приложение Spring MVC. Однако, если мы реализуем REST API, мы хотим преобразовать исключения в коды состояния HTTP. Это поведение обеспечивается классом ResponseStatusExceptionResolver, который включен по умолчанию.

В нашем примере приложения также есть пользовательский класс обработчика исключений, который аннотируется аннотацией @ControllerAdvice . Этот класс обрабатывает ошибки проверки и специфичные для приложения исключения. Подробнее об этом классе мы поговорим позже в этом посте.

Давайте продолжим и узнаем, как мы можем написать модульные тесты для нашего REST API.

Написание модульных тестов для REST API

Прежде чем мы начнем писать модульные тесты для нашего REST API, нам нужно понять две вещи:

  • Нам нужно знать, каковы основные компоненты среды Spring MVC Test. Эти компоненты описаны во второй части этого урока .
  • Нам нужно знать, как мы можем писать утверждения для документов JSON, используя выражения JsonPath. Мы можем получить эту информацию, прочитав мой пост в блоге, который описывает, как мы можем написать чистые утверждения с помощью JsonPath .

Далее мы увидим платформу Spring MVC Test в действии и напишем модульные тесты для следующих методов контроллера:

  • Первые методы контроллера возвращают список записей todo.
  • Второй метод контроллера возвращает информацию об одной записи todo.
  • Третий метод контроллера добавляет новую запись todo в базу данных и возвращает добавленную запись todo.
Читайте также:  Setting file type in java

Получить записи Todo

Первый метод контроллера возвращает список записей todo, найденных в базе данных. Давайте начнем с рассмотрения реализации этого метода.

Ожидаемое поведение

Метод контроллера, который возвращает все записи todo, хранящиеся в базе данных, реализуется с помощью следующих шагов:

  1. Он обрабатывает запросы GET, отправленные на URL / api / todo.
  2. Он получает список объектов Todo , вызывая метод findAll () интерфейса TodoService . Этот метод возвращает все записи, которые хранятся в базе данных. Эти записи todo всегда возвращаются в одном и том же порядке.
  3. Преобразует полученный список в список объектов TodoDTO .
  4. Возвращает список, содержащий объекты TodoDTO .

Соответствующая часть класса TodoController выглядит следующим образом:

Источник

Оцените статью