/
elendi
/
simple-crud
Обзор
Документация
Войти
/
elendi
/
simple-crud
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/test/java/com/example/crud/UserControllerIntegrationTest.java
163 строки
7 KB
elendilearner
аудит и тесты
04 мар 2026, 07:00
04 мар 2026, 07:00
4243b8e
Код
Авторство
О чём код?
package com.example.crud; import com.example.crud.audit.AuditService; import com.example.crud.audit.event.*; import com.example.crud.dto.UserRequest; import com.example.crud.dto.UserResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.*; import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; /** * Интеграционные тесты для {@link com.example.crud.controller.UserController}. * * <p>Поднимает полноценный Spring-контекст на случайном порту ({@code RANDOM_PORT}) * и выполняет реальные HTTP-запросы через {@link RestTemplate}, * проверяя корректность ответов для всех CRUD-операций.</p> * * <p>Дополнительно проверяет, что {@link AuditService#publish} вызывается * с корректным типом события после каждой операции.</p> * * <p>Тесты покрывают следующие сценарии: * <ul> * <li>Получение списка всех пользователей</li> * <li>Получение пользователя по ID</li> * <li>Создание нового пользователя</li> * <li>Обновление существующего пользователя</li> * <li>Удаление пользователя</li> * </ul> * </p> */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class UserControllerIntegrationTest { /** * Случайный порт, на котором поднимается сервер во время теста. * Автоматически инжектируется Spring после старта контекста. */ @LocalServerPort private int port; /** * Шпион над реальным бином {@link AuditService}. * Позволяет проверять вызовы метода {@code publish} без замены реализации. */ @SpyBean private AuditService auditService; /** * HTTP-клиент для выполнения запросов к запущенному серверу. */ private RestTemplate restTemplate; /** * Базовый URL для обращения к эндпоинтам пользователей. * Формируется из {@code port} перед каждым тестом. */ private String baseUrl; /** * Инициализирует {@link RestTemplate} и формирует базовый URL перед каждым тестом. */ @BeforeEach void setUp() { restTemplate = new RestTemplate(); baseUrl = "http://localhost:" + port + "/api/users"; } /** * Проверяет, что {@code GET /api/users} возвращает HTTP 200, * непустой список пользователей и публикует {@link UserFetchedAllEvent}. */ @Test void getAll_shouldReturnListOfUsersAndPublishAuditEvent() { ResponseEntity<UserResponse[]> response = restTemplate.getForEntity(baseUrl, UserResponse[].class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody()).hasSizeGreaterThan(0); verify(auditService).publish(any(UserFetchedAllEvent.class)); } /** * Проверяет, что {@code GET /api/users/{id}} возвращает HTTP 200, * пользователя с корректным {@code id} и публикует {@link UserFetchedEvent}. */ @Test void getById_shouldReturnUserAndPublishAuditEvent() { ResponseEntity<UserResponse> response = restTemplate.getForEntity(baseUrl + "/1", UserResponse.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getId()).isEqualTo(1L); verify(auditService).publish(any(UserFetchedEvent.class)); } /** * Проверяет, что {@code POST /api/users} возвращает HTTP 201, * созданного пользователя с переданными данными и публикует {@link UserCreatedEvent}. */ @Test void create_shouldReturnCreatedUserAndPublishAuditEvent() { UserRequest request = new UserRequest(); request.setName("Ivan"); request.setEmail("ivan@example.com"); ResponseEntity<UserResponse> response = restTemplate.postForEntity(baseUrl, request, UserResponse.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getName()).isEqualTo("Ivan"); assertThat(response.getBody().getEmail()).isEqualTo("ivan@example.com"); verify(auditService).publish(any(UserCreatedEvent.class)); } /** * Проверяет, что {@code PUT /api/users/{id}} возвращает HTTP 200, * пользователя с обновлёнными данными и публикует {@link UserUpdatedEvent}. */ @Test void update_shouldReturnUpdatedUserAndPublishAuditEvent() { UserRequest request = new UserRequest(); request.setName("Updated"); request.setEmail("updated@example.com"); HttpEntity<UserRequest> entity = new HttpEntity<>(request); ResponseEntity<UserResponse> response = restTemplate.exchange( baseUrl + "/1", HttpMethod.PUT, entity, UserResponse.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).isNotNull(); assertThat(response.getBody().getName()).isEqualTo("Updated"); assertThat(response.getBody().getEmail()).isEqualTo("updated@example.com"); verify(auditService).publish(any(UserUpdatedEvent.class)); } /** * Проверяет, что {@code DELETE /api/users/{id}} возвращает HTTP 204 * и публикует {@link UserDeletedEvent}. */ @Test void delete_shouldReturnNoContentAndPublishAuditEvent() { ResponseEntity<Void> response = restTemplate.exchange( baseUrl + "/1", HttpMethod.DELETE, null, Void.class ); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); verify(auditService).publish(any(UserDeletedEvent.class)); } }