Java Spring 기반에서 Mock Server와 AOP를 결합한 테스트 전략을 실제 코드 예제와 함께 설명해 드리겠습니다. 아래는 외부 결제 API를 호출하는 서비스를 예제로 설정한 것입니다.
---
🌐 시나리오 설정
PaymentService는 외부 결제 시스템(예: KakaoPay, Toss 등)에 HTTP 요청을 보냄.
실제 호출 대신, 테스트 시에는 Mock Server로 우회하고,
그 우회를 AOP로 처리하여 코드에 변경 없이 테스트 환경을 구성함.
---
1️⃣ 외부 API 인터페이스
public interface PaymentApiClient {
PaymentResponse requestPayment(PaymentRequest request);
}
---
2️⃣ 실제 API 호출 구현 (RestTemplate 예시)
@Service
@Profile("prod")
public class RealPaymentApiClient implements PaymentApiClient {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public PaymentResponse requestPayment(PaymentRequest request) {
ResponseEntity<PaymentResponse> response = restTemplate.postForEntity(
"https://api.payment.com/pay",
request,
PaymentResponse.class
);
return response.getBody();
}
}
---
3️⃣ 테스트용 Mock Server 설정 (예: WireMock)
✅ 설정 (JUnit 5 기반)
@ExtendWith(SpringExtension.class)
@SpringBootTest
@ActiveProfiles("test")
public class PaymentServiceTest {
static WireMockServer wireMockServer;
@BeforeAll
static void setupMockServer() {
wireMockServer = new WireMockServer(8089);
wireMockServer.start();
WireMock.configureFor("localhost", 8089);
WireMock.stubFor(post(urlEqualTo("/pay"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody("{ \"status\": \"SUCCESS\", \"message\": \"결제 완료\" }")));
}
@AfterAll
static void teardown() {
wireMockServer.stop();
}
@Autowired
PaymentService paymentService;
@Test
public void testMockedPayment() {
PaymentResponse response = paymentService.pay(new PaymentRequest(...));
assertEquals("SUCCESS", response.getStatus());
}
}
---
4️⃣ 테스트용 Mock API 클라이언트 구현
@Service
@Profile("test")
public class MockPaymentApiClient implements PaymentApiClient {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public PaymentResponse requestPayment(PaymentRequest request) {
// WireMock이 8089 포트에서 mock 응답 제공
return restTemplate.postForObject("http://localhost:8089/pay", request, PaymentResponse.class);
}
}
---
5️⃣ AOP로 동적 우회 (고급 전략)
✅ 커스텀 어노테이션 정의
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseMockServer {
}
✅ AOP 구현
@Aspect
@Component
@Profile("test")
public class PaymentMockAspect {
@Around("@annotation(UseMockServer)")
public Object interceptWithMock(ProceedingJoinPoint joinPoint) throws Throwable {
// 필요 시 조건 추가 가능
System.out.println("🔁 Mock 서버로 요청 우회 중");
return joinPoint.proceed();
}
}
✅ 테스트 대상 서비스
@Service
public class PaymentService {
private final PaymentApiClient paymentApiClient;
public PaymentService(PaymentApiClient paymentApiClient) {
this.paymentApiClient = paymentApiClient;
}
@UseMockServer
public PaymentResponse pay(PaymentRequest request) {
return paymentApiClient.requestPayment(request);
}
}
---
✅ 정리
기술 사용 이유 이점
Mock Server (WireMock) 외부 API를 실제 호출 없이 모방 테스트 안정성, 속도, 제어력 향상
AOP 테스트 상황에서 실행 흐름 감시 / 제어 코드 침투 없이 mock 로직 주입 가능
@Profile 환경별 Bean 분리 운영과 테스트 분리
---
🧠 추가 팁
@Profile 을 적극 활용해, test 환경에서는 mock, prod 환경에서는 실제 서비스 자동 사용.
Spring Cloud Contract 등으로 WireMock 자동화 가능.
RestTemplate 대신 WebClient 사용 시에도 유사 구조로 적용 가능.
---
원하시면 Gradle 세팅, 전체 프로젝트 구조, 또는 Spring Cloud Contract 기반 테스트 예제도 이어서 제공해 드릴 수 있어요. 어떤 방향이 더 궁금하신가요?
'4차산업혁명의 일꾼 > Spring' 카테고리의 다른 글
동시성테스트 (0) | 2025.06.19 |
---|---|
테스트 전략에서 Mock Server와 **AOP (Aspect-Oriented Programming)**를 활용하는 방식 (0) | 2025.06.04 |
스프링7에서 도입되는것 (4) | 2025.05.28 |
JWT 생성과 시큐리티 필터 연계 (0) | 2024.12.26 |
스프링부트에서 React 연결 (0) | 2024.12.26 |