아래는 **"스프링부트 웹플럭스 시리즈"**의 **8장: 웹플럭스에서의 테스트"**에 대한 초안입니다. 7장에서 만든 REST API를 기반으로 `WebTestClient`를 활용한 테스트를 다루며, 단위 테스트와 통합 테스트 예제를 포함했습니다. 코드도 간략히 유지하며 초보자가 따라 하기 쉽게 자연스러운 문체로 작성했습니다. --- ## 8. 웹플럭스에서의 테스트 7장에서 REST API를 완성했으니, 이제 제대로 작동하는지 확인해볼 차례입니다. 웹플럭스는 비동기 특성 때문에 테스트 방식이 기존 스프링 MVC와 조금 다릅니다. 이번 장에서는 `WebTestClient`를 사용해 웹플럭스 애플리케이션을 테스트하는 방법을 배워보겠습니다. 단위 테스트와 통합 테스트를 실습하며, 모킹과 비동기 테스트 팁도 함께 다룰게요. 준비되셨죠? ### WebTestClient를 활용한 테스트 작성 `WebTestClient`는 웹플럭스 애플리케이션의 HTTP 엔드포인트를 테스트하기 위한 도구입니다. 실제 서버를 띄우거나 모킹된 환경에서 테스트할 수 있어 유연합니다. 먼저, 테스트 의존성이 `build.gradle`에 있는지 확인하세요 (3장에서 추가했어야 함): ```gradle testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.projectreactor:reactor-test' ``` ### 단위 테스트 예제 먼저, `UserController`의 로직을 단위 테스트로 검증해보겠습니다. 데이터베이스 호출을 모킹하여 컨트롤러만 테스트합니다. `src/test/java/com/example/demo`에 `UserControllerTest` 클래스를 만듭니다: ```java package com.example.demo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono; import static org.mockito.Mockito.when; @WebFluxTest(UserController.class) public class UserControllerTest { @Autowired private WebTestClient webTestClient; @MockBean private UserRepository userRepository; @Test public void testGetUserById() { User user = new User(); user.setId(1L); user.setName("Alice"); user.setEmail("alice@example.com"); when(userRepository.findById(1L)).thenReturn(Mono.just(user)); webTestClient.get() .uri("/users/1") .exchange() .expectStatus().isOk() .expectBody(User.class) .isEqualTo(user); } @Test public void testGetUserNotFound() { when(userRepository.findById(999L)).thenReturn(Mono.empty()); webTestClient.get() .uri("/users/999") .exchange() .expectStatus().isNotFound() .expectBody(String.class) .isEqualTo("User with ID 999 not found"); } } ``` - `@WebFluxTest`: 컨트롤러만 테스트하도록 웹플럭스 환경을 설정. - `@MockBean`: `UserRepository`를 모킹하여 실제 DB 호출을 대체. - `WebTestClient`: GET 요청을 보내고 응답을 검증. `testGetUserById`는 성공 케이스, `testGetUserNotFound`는 404 에러 케이스를 테스트합니다. `./gradlew test`로 실행하면 결과가 콘솔에 표시됩니다. ### 통합 테스트 예제 이번엔 실제 데이터베이스와 연동한 통합 테스트를 해보겠습니다. `src/test/java/com/example/demo`에 `UserControllerIntegrationTest`를 추가합니다: ```java package com.example.demo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class UserControllerIntegrationTest { @Autowired private WebTestClient webTestClient; @Autowired private UserRepository userRepository; @Test public void testCreateAndGetUser() { User user = new User(); user.setName("Bob"); user.setEmail("bob@example.com"); webTestClient.post() .uri("/users") .body(Mono.just(user), User.class) .exchange() .expectStatus().isCreated() .expectBody(User.class) .value(savedUser -> { webTestClient.get() .uri("/users/" + savedUser.getId()) .exchange() .expectStatus().isOk() .expectBody(User.class) .isEqualTo(savedUser); }); } } ``` - `@SpringBootTest`: 전체 애플리케이션 컨텍스트를 로드하며, 랜덤 포트로 서버를 띄움. - `testCreateAndGetUser`: 사용자를 생성하고, 생성된 ID로 조회까지 테스트. 이 테스트는 실제 MariaDB와 연동되므로, `application.yaml`의 설정이 올바른지 확인하세요. ### 모킹과 비동기 테스트 팁 1. **모킹 활용**: `Mockito`로 리포지토리나 외부 서비스를 모킹하면 의존성을 줄이고 빠르게 테스트할 수 있습니다. 단위 테스트에서 유용하죠. 2. **비동기 처리 확인**: `StepVerifier`를 사용하면 `Mono`나 `Flux`의 비동기 흐름을 더 정밀하게 검증할 수 있습니다. 예를 들어: ```java @Test public void testMonoWithStepVerifier() { User user = new User(); user.setId(1L); user.setName("Alice"); when(userRepository.findById(1L)).thenReturn(Mono.just(user)); Mono userMono = userRepository.findById(1L); StepVerifier.create(userMono) .expectNext(user) .verifyComplete(); } ``` - `StepVerifier`: 리액티브 스트림의 이벤트를 단계별로 검증. 3. **타임아웃 설정**: 비동기 테스트가 너무 오래 걸리면 실패로 간주하도록 설정하세요. `WebTestClient`에 `.responseTimeout(Duration.ofSeconds(5))`를 추가할 수 있습니다. ### 테스트 실행해보기 _ `./gradlew test`를 실행하면 단위 테스트와 통합 테스트가 모두 실행됩니다. 콘솔에서 성공/실패 여부를 확인할 수 있습니다. 통합 테스트는 MariaDB가 실행 중이어야 하니, 서버가 켜져 있는지 체크하세요. ### 마무리 `WebTestClient`로 웹플럭스 API를 테스트하며, 단위 테스트와 통합 테스트의 차이도 경험해봤습니다. 비동기 환경에서의 테스트는 처음엔 낯설 수 있지만, 익숙해지면 애플리케이션의 안정성을 크게 높일 수 있습니다. 다음 장에서는 성능 최적화와 디버깅을 다루며, 웹플럭스를 실무에서 더 단단하게 다듬는 법을 배워보겠습니다. 테스트 작성의 재미를 느끼셨길 바랍니다! --- 이 장은 `WebTestClient`를 중심으로 실습을 구성했으며, 단위/통합 테스트와 비동기 팁을 간결히 다뤘습니다. 추가 예제나 수정이 필요하면 말씀해주세요!