2025-04-08T19:56:24

This commit is contained in:
2025-04-08 19:56:24 +09:00
parent a75a1dbd0f
commit eef061c1c9
100 changed files with 18639 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
아래는 **"스프링부트 웹플럭스 시리즈"**의 **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<User> userMono = userRepository.findById(1L);
StepVerifier.create(userMono)
.expectNext(user)
.verifyComplete();
}
```
- `StepVerifier`: 리액티브 스트림의 이벤트를 단계별로 검증.
3. **타임아웃 설정**: 비동기 테스트가 너무 오래 걸리면 실패로 간주하도록 설정하세요. `WebTestClient``.responseTimeout(Duration.ofSeconds(5))`를 추가할 수 있습니다.
### 테스트 실행해보기 _
`./gradlew test`를 실행하면 단위 테스트와 통합 테스트가 모두 실행됩니다. 콘솔에서 성공/실패 여부를 확인할 수 있습니다. 통합 테스트는 MariaDB가 실행 중이어야 하니, 서버가 켜져 있는지 체크하세요.
### 마무리
`WebTestClient`로 웹플럭스 API를 테스트하며, 단위 테스트와 통합 테스트의 차이도 경험해봤습니다. 비동기 환경에서의 테스트는 처음엔 낯설 수 있지만, 익숙해지면 애플리케이션의 안정성을 크게 높일 수 있습니다. 다음 장에서는 성능 최적화와 디버깅을 다루며, 웹플럭스를 실무에서 더 단단하게 다듬는 법을 배워보겠습니다. 테스트 작성의 재미를 느끼셨길 바랍니다!
---
이 장은 `WebTestClient`를 중심으로 실습을 구성했으며, 단위/통합 테스트와 비동기 팁을 간결히 다뤘습니다. 추가 예제나 수정이 필요하면 말씀해주세요!