JavaRush /Курси /Модуль 5. Spring /Короткий зміст попередніх лекцій

Короткий зміст попередніх лекцій

Модуль 5. Spring
Рівень 9 , Лекція 3
Відкрита

От і дісталися до тестування контролерів. Контролери, як знаєте, відповідають за обробку HTTP-запитів і передачу даних між клієнтом і бізнес-логікою застосунку. Усі хочуть, щоб їхні контролери працювали бездоганно, але хтось має це перевірити. Спойлер: цим кимось будете ви. На щастя, у нас є потужний інструмент — MockMvc.

Навіщо тестувати контролери? Ну по-перше, тестування контролерів дає впевненість, що ваші ендпоінти працюють (і не тільки в вашому браузері).

По-друге, контролери часто є першим елементом застосунку, на який падає весь гнів користувачів у разі помилок. Наприклад, що зробить користувач, якщо запит по URI /api/users повертає 500 Internal Server Error? Звісно, звинуватить ваш код (і, можливо, вас особисто). Тож якщо ваш код працює — ви в безпеці.


Що таке MockMvc?

MockMvc — це інструмент, який надає Spring Test і який дозволяє тестувати поведінку веб-застосунків без необхідності розгортання реального сервера. Він імітує обробку HTTP-запитів і дає змогу перевіряти відповіді, заголовки, статуси й навіть помилки.

MockMvc дозволяє відправляти тестові HTTP-запити до ваших контролерів і перевіряти, як вони на них відповідають. Наприклад, можна відправити GET-запит на /api/users і перевірити, що статус відповіді — 200, а тіло містить очікувані дані.

Ось невеликий приклад взаємодії з MockMvc:


mockMvc.perform(get("/api/users"))
    .andExpect(status().isOk())
    .andExpect(content().json("[{\"id\":1,\"name\":\"John Doe\"}]"));

Підготовка до тестування

Перед тим як почати писати тести, давайте переконаємось, що в нас є все необхідне:

  1. Контролер: напишемо приклад контролера, який будемо тестувати.
  2. Залежності: додамо Spring Boot Test, JUnit і Mockito для роботи.
  3. Конфігурація MockMvc: налаштуємо MockMvc для тестів.

Крок 1: Приклад контролера для тестування

Припустимо, у нас є контролер для роботи з користувачами:


@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

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

    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
}

Контролер містить два ендпоінти:

  • GET /api/users — повертає список користувачів.
  • POST /api/users — додає нового користувача.

Крок 2: Налаштування залежностей у pom.xml

Додамо потрібні залежності для тестування:


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

Крок 3: Написання тестів для контролера

Тепер створимо тестовий клас для UserController.

Імпортуємо потрібні класи


import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

Налаштуємо клас тестів


@WebMvcTest(UserController.class)
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    // Тут будемо писати тести
}

Крок 4: Тестування GET /api/users

Напишемо тест, щоб перевірити, що GET /api/users повертає коректний список користувачів.


@Test
public void shouldReturnListOfUsers() throws Exception {
    // Створюємо тестові дані
    List<User> users = List.of(new User(1L, "John Doe"), new User(2L, "Jane Doe"));

    // Налаштовуємо поведінку мока
    when(userService.findAll()).thenReturn(users);

    // Відправляємо GET-запит і перевіряємо результат
    mockMvc.perform(get("/api/users"))
           .andExpect(status().isOk())
           .andExpect(jsonPath("$.size()").value(users.size()))
           .andExpect(jsonPath("$[0].name").value("John Doe"))
           .andExpect(jsonPath("$[1].name").value("Jane Doe"));
}

Що тут відбувається:

  1. Створюємо список користувачів для тесту.
  2. Налаштовуємо мок userService, щоб він повертав цей список при виклику findAll().
  3. Робимо GET-запит на /api/users.
  4. Перевіряємо:
    • Статус відповіді (200 OK).
    • Розмір списку в JSON-відповіді.
    • Значення поля name у користувачів.

Крок 5: Тестування POST /api/users

Тестуємо, що POST /api/users створює нового користувача.


@Test
public void shouldCreateNewUser() throws Exception {
    // Створюємо тестового користувача
    User newUser = new User(null, "John Doe");
    User savedUser = new User(1L, "John Doe");

    // Налаштовуємо поведінку мока
    when(userService.save(any(User.class))).thenReturn(savedUser);

    // Відправляємо POST-запит і перевіряємо результат
    mockMvc.perform(post("/api/users")
           .contentType(MediaType.APPLICATION_JSON)
           .content("{\"name\":\"John Doe\"}"))
           .andExpect(status().isCreated())
           .andExpect(jsonPath("$.id").value(1))
           .andExpect(jsonPath("$.name").value("John Doe"));
}

Тут:

  1. Ми відправляємо POST-запит з JSON-об'єктом.
  2. Перевіряємо, що:
    • Статус відповіді — 201 Created
    • Відповідь містить ID і ім'я нового користувача.

Корисні поради

  1. Не забувайте про edge cases: тестуйте не тільки позитивні сценарії, а й негативні. Наприклад, що відбувається, якщо відправити некоректні дані.
  2. Використовуйте зручні методи: MockMvc надає купу корисних методів, таких як jsonPath(), header() тощо.
  3. Прибирайте після себе: нехай ваші тести не залежать від стану попередніх тестів. Кожен тест має бути незалежним.

Що далі?

Тепер ви вмієте тестувати REST-контролери з використанням MockMvc. Це не тільки корисно для забезпечення якості, а й класно виглядає в резюме. У наступній лекції зосередимося на тестуванні сервісів і репозиторіїв. А поки — озбройтеся знаннями й ідіть тестувати свої контролери!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ