자동 계약 테스트 끝판왕 가이드:
서론: 왜 계약 테스트인가
• 서비스 간 불일치 방지: REST·gRPC·메시지 큐로 연결된 마이크로서비스 간 스펙 충돌 없이 안전 보장
• 통합 테스트 비용 절감: 실제 환경 프로비저닝 없이 소비자·제공자 계약으로 상호 검증
• CI 단계 전면 통합: 계약 위반 시 PR 차단 → 배포 파이프라인 중단
• Event-Driven 환경 지원: Kafka, RabbitMQ 등 메시지 버스 계약도 자동화
실리콘밸리·심천 IT기업 톱티어 팀들은 Pact(HTTP & 메시지), Spring Cloud Contract, Pact-Kafka를 결합해, 계약 정의→게시→검증→배포 전 자동화된 Contract-First 워크플로우를 설계합니다.
⸻
아키텍처 개관
Consumer Repo Pact Broker Provider Repo CI/CD Pipeline Message Broker
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────┐
│ Pact Consumer │──▶ │ Pact Broker │◀───▶│ Pact Provider │────▶ │ GitHub Actions│ │ Kafka Cluster│
│ 테스트 생성 │ │ 저장소 │ │ 검증 모듈 │ │ - 계약 게시 │ └───────────┘
└───────────────┘ └───────────────┘ └───────────────┘ │ - 계약 다운로드│
│ - Provider 검증│
│ - 메시지 계약 검증│
└───────────────┘
1. Consumer: Pact DSL로 예상 요청·응답 계약 정의
2. Pact Broker: 중앙 계약 레지스트리
3. Provider: Spring Cloud Contract 및 Pact 검증
4. Pact-Kafka: 메시지 기반 계약 테스트
5. CI/CD: GitHub Actions로 계약 게시·다운로드·검증 자동화
⸻
Pact HTTP 계약 테스트
Consumer 측 정의 (Java JUnit 예시)
@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(provider="user-service", port="8081")
class UserClientPactTest {
@Pact(consumer="order-service")
public RequestResponsePact createPact(PactDslWithProvider p) {
return p
.given("user exists", Map.of("userId", 123))
.uponReceiving("get user by id")
.path("/users/123")
.method("GET")
.willRespondWith()
.status(200)
.body(new PactDslJsonBody()
.integerType("id", 123)
.stringType("name", "Alice"))
.toPact();
}
@Test
void testGetUser(MockServer mockServer) {
UserClient client = new UserClient(mockServer.getUrl());
User user = client.getUser(123);
assertEquals("Alice", user.getName());
}
}
Pact Broker에 계약 게시
- name: Publish Pact to Broker
run: |
./gradlew pactPublish \
-DpactBrokerUrl=${{ secrets.PACT_BROKER_URL }} \
-DpactBrokerToken=${{ secrets.PACT_BROKER_TOKEN }}
⸻
Spring Cloud Contract Provider 검증
Gradle 설정
dependencies {
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
}
contracts {
baseClassForTests = 'com.myorg.ContractBase'
packageWithBaseClasses = 'com.myorg'
testMode = 'JUNIT5'
}
검증 실행
- name: Verify Provider Contracts
run: ./gradlew clean contractTest
• Pact Broker에서 최신 계약을 다운로드해 Spring 서비스에 대한 검증 수행
⸻
Kafka 메시지 계약 테스트 (Pact-Kafka)
Consumer 메시지 계약 예시 (Java)
@Pact(consumer="inventory-service", provider="order-service")
public MessagePact createKafkaPact(MessagePactBuilder builder) {
return builder
.expectsToReceive("order.created event")
.withContent(new PactDslJsonBody()
.integerType("orderId", 456)
.stringType("status", "CREATED"))
.toPact();
}
@Test
void testOrderCreatedPact(MockMessagePact mockPact) {
// Pact-JVM Kafka 모듈로 메시지 디코딩 후 컨슈머 로직 검증
}
Provider 메시지 발행 검증
- name: Verify Kafka Provider
run: |
./gradlew pactVerify \
-DpactBrokerUrl=${{ secrets.PACT_BROKER_URL }} \
-DpactBrokerToken=${{ secrets.PACT_BROKER_TOKEN }}
⸻
GitHub Actions 통합 워크플로우
name: Contract Testing
on:
pull_request:
paths:
- 'consumer/**'
- 'provider/**'
- 'contracts/**'
jobs:
publish:
if: startsWith(github.ref, 'refs/heads/consumer-')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Publish Consumer Pact
run: ./gradlew pactPublish \
-DpactBrokerUrl=${{ secrets.PACT_BROKER_URL }} \
-DpactBrokerToken=${{ secrets.PACT_BROKER_TOKEN }}
verify-http:
needs: publish
if: github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify HTTP Provider
run: ./gradlew clean contractTest
verify-kafka:
needs: publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Verify Kafka Provider
run: ./gradlew pactVerify \
-DpactBrokerUrl=${{ secrets.PACT_BROKER_URL }} \
-DpactBrokerToken=${{ secrets.PACT_BROKER_TOKEN }}
• publish: Consumer 브랜치에서만 계약 게시
• verify-http/verify-kafka: main 브랜치 PR에 대해 실행
⸻
고급 팁 & “아, 이런 방법도”
1. Branch Tag Versioning: Pact 브로커에 브랜치 태그별로 격리된 계약 관리
2. Contract Rollforward: 위반 시 자동 PR 생성 → Consumer 수정 유도
3. Continuous Replay: Pact Broker 웹훅 → CI 재검증 파이프라인 트리거
4. Consumer-Driven Mock Server: WireMock + Pact Stub Runner로 독립 테스트
5. Security Contracts: 계약에 authentication 조건 포함 → 보안 테스트 자동화
⸻
결론
• Pact로 HTTP·메시지 계약을 정의·게시
• Spring Cloud Contract로 스프링 서비스 검증
• Pact-Kafka로 이벤트 기반 메시지 계약 자동화
• GitHub Actions로 전 과정 CI/CD 통합
“교과서론 결코 알려주지 않는, 실리콘밸리·심천 IT기업 최정예 엔지니어급 자동 계약 테스트”를 지금 바로 구현해 보세요. 서비스 간 계약 위반 제로, 배포 안전성 100% 그날까지!
'IT & Tech 정보' 카테고리의 다른 글
무중단 데이터 마이그레이션 자동화: 온라인 스키마 변경 with gh-ost + Argo Workflows (0) | 2025.05.28 |
---|---|
Helm + GitOps + SecretOps: 프로덕션 등급 Kubernetes 배포를 위한 완전체 구성 전략 (0) | 2025.05.28 |
자동 롤백 전략 끝판왕 가이드: Helm + Kubernetes Liveness/Readiness 프로브 (0) | 2025.05.26 |
Chaos Engineering 통합 끝판왕 가이드: Chaos Mesh & LitmusChaos CI 파이프라인 (0) | 2025.05.26 |
AI 기반 테스트 우선순위화 끝판왕 가이드: ML 모델로 Test Suite 최적화 (0) | 2025.05.26 |