계약 테스팅(Contract Testing)은 서비스 간 API 계약을 소비자(Consumer) 주도로 정의하고 검증하는 테스팅 기법이다. Pact가 가장 널리 쓰이는 도구이며, 마이크로서비스 환경에서 통합 테스트 대체제로 사용된다.
통합 테스트와 비교
| 항목 | 통합 테스트 | 계약 테스팅 |
|---|
| 의존성 | 실제 서비스 필요 | 목(Pact Mock) 사용 |
| 실행 속도 | 느림 | 빠름 |
| 실패 원인 | 모호 | 계약 위반 명확 |
| 환경 | 공유 환경 필요 | 독립 실행 |
| 적합 규모 | 소규모 | 마이크로서비스 |
Pact 흐름
1. Consumer(소비자)가 기대 인터랙션을 Pact 파일에 기록
POST /users { name: "Alice" } → 201 { id: 1, name: "Alice" }
2. Consumer 테스트 실행 → pact/consumer-provider.json 생성
3. Pact Broker에 계약 파일 게시
4. Provider(제공자)가 Pact Broker에서 계약 가져와 검증
실제 서비스 기동 후 계약 재생 → 응답 비교
5. 불일치 시 빌드 실패 → 즉각 피드백
typescript
import { Pact } from '@pact-foundation/pact';
import { like, term } from '@pact-foundation/pact/src/dsl/matchers';
const provider = new Pact({
consumer: 'UserApp',
provider: 'UserService',
port: 1234,
});
describe('User API Contract', () => {
before(() => provider.setup());
after(() => provider.finalize());
it('gets user by id', async () => {
await provider.addInteraction({
state: 'user 1 exists',
uponReceiving: 'GET /users/1',
withRequest: { method: 'GET', path: '/users/1' },
willRespondWith: {
status: 200,
body: {
id: like(1),
name: like('Alice'),
email: term({ generate: 'alice@example.com', matcher: '.+@.+' }),
},
},
});
const user = await fetchUser(1); // 실제 클라이언트 코드
expect(user.id).toBe(1);
});
});
Pact Broker
역할:
- 계약 파일 중앙 저장소
- can-i-deploy: 배포 안전성 확인
- 계약 버전 관리
- 웹 UI로 의존 관계 시각화
PactFlow (SaaS): 엔터프라이즈 기능 포함
관련 문서
- •[[api-testing|API 테스팅]]
- •[test-doubles|[테스트 더블]]
- •[microservices|[마이크로서비스]]