계약 테스트
1) 계약 신청 장소
HTP REST/JSON: 리소스, 페이지 매김, 필터, demempotency, 오류 코드.
gRPC/프로토 타입: 메시지 유형, 상태, '마감일' 의미론, 역 컴파트 v.프로토.
GraphQL: 스키마, 비널, 지침, 필드에 허용됩니다.
메시지/스트림 (Kafka/Pulsar/SQS): 이벤트 체계 (Avro/JSON/Protoguy), 파티션 키, 순서, demempotent 키.
내부 SDK/라이브러리: 공개 기능/예외/성과 계약.
2) CDC 모델: 역할 및 아티팩트
소비자는 기대 계약 (샘플 요청/응답, 유형 매처, 불변량) 을 발표합니다.
공급 업체는 서비스/어댑터/핸들러에 대해 계약 검증을 실행합니다.
계약 중개인 (Pact Broker/Backstage/repo artifact) 은 버전, 태그 ('prod', 'staging', 'canary') 및 'suvier @ v → provesser @ v' 호환성 매트릭스를 저장합니다.
릴리스 정책: "prod 관련" 계약을 위반하면 공급자를 보내는 것은 금지됩니다.
3) 계약에서 수정해야 할 사항 (HTP 예)
최소값:- 방법/경로/매개 변수/헤더 (Auth, demempotent 키 참조).
- 신체 및 전형적인 성냥갑 (유형/형식/regexp/range).
- 오류 코드 및 구조; 안정적인 '오류 _ 코드'.
- 시맨틱 불변: 정렬, 독창성, 단조 '생성 _ at'.
- 비 기능 기대 (선택 사항): p95, 크기 제한, 속도 제한 헤더.
json
{
"interaction": "GET /v1/users/{id}",
"request": { "method": "GET", "path": "/v1/users/123", "headers": {"Accept":"application/json"} },
"matchers": {
"response.body.id": "type:number",
"response.body.email": "regex:^.+@.+\\..+$",
"response.body.created_at": "format:rfc3339"
},
"response": {
"status": 200,
"headers": {"Content-Type":"application/json"},
"body": {"id": 123, "email": "alice@example.com", "created_at": "2025-10-31T12:00:00Z"}
},
"error_cases": [
{
"name":"not_found",
"request":{"path":"/v1/users/9999"},
"response":{"status":404, "body":{"error_code":"USER_NOT_FOUND"}}
}
]
}
4) 이벤트 중심 계약
이벤트 스키마: '유형', '버전', 'id', 'arsed _ at _ utc', '프로듀서', '주제', '페이로드'.
불변량: 불변 'id' 및 '(유형, id)' 에 의한 불변, 부분의 키 내에서 순서, 단조 '시퀀스'.
Schema Registry-Stores 진화 및 호환성 규칙 (이전/정방향/전체).
소비자 계약 테스트: "골든" 이벤트 및 네거티브 단계 (알 수없는 필드, 무효화 가능) 를 재생합니다.
json
{
"type":"record","name":"UserRegistered","namespace":"events.v1",
"fields":[
{"name":"id","type":"string"},
{"name":"occurred_at_utc","type":{"type":"long","logicalType":"timestamp-millis"}},
{"name":"email","type":"string"},
{"name":"marketing_opt_in","type":["null","boolean"],"default":null}
]
}
5) 진화와 호환성
계약 버전: 'MAJOR' 의미론. 미노르. PATCH '(MAJOR-breaking).
REST 규칙:- 파기하지 마십시오: 필드를 삭제하지 말고 유형/값 '오류 _ 코드' 를 변경하지 마십시오.
- 기본값으로 선택한 필드를 추가합 "매직" 대신 새로운 엔드 포인트.
- 감소: 선언, 동시 지원, 지표 별 삭제.
- GraphQL: 추가 전용 필드, 비 널은 단계를 통해 입력됩니다. 선언 지침.
- gRPC/프로토: 필드 번호를 재사용하지 마십시오. 옵션이있는 새 것만 추가하십시오.
- 이벤트: 제도 'vN'; 소비자는 알려지지 않은 필드 (leniency) 를 무시해야합니다.
6) 부정적이고 변하지 않는 점검
부정적: 잘못된 유형, 금지 된 값, 상충되는 매개 변수, 한계를 초과 함.
불변량: 반복 될 때 응답 정렬, 'id' 의 독창성, 'Next _ curder' 의 정확성, dempotent 반응의 안정성.
임시 측면의 계약: '만들어진' RFC3339/UTC, 현지 일의 올바른 예측은 운송 계약의 일부가 아닙니다-비즈니스 불변자에게 제출됩니다.
7) 스탭 생성 및 지역 개발
계약에서 공급자 스택은 소비자 개발을 위해 생성됩니다.
이벤트의 경우-체계에 따른 "유효한/경계선" 메시지 생성기.
직원은 계약 버전과 구축 날짜로 표시됩니다. prod로 출판.
8) CI/CD에 포함 (참조 파이프 라인)
1. 소비자 CI:
Lint/build → 계약 생성 → 계약 중개인의 단위/테스트 계약 → 출판 (태그: '소비자 @ 1. 7. 0`).
2. 공급자 CI:
컨테이너에서 로컬/컨테이너에서 서비스를 올리면 관련 계약 ('prod '/' staging') → 브로커 상태의 확인 → 게시가 가져옵니다.
3. 출시 게이트:
미결제 계약이있는 경우 공급자의 배포가 차단됩니다.
4. 야간 매트릭스:
호환성 행렬 '소비자 버전 × 공급자 버전'; 보고서 및 경보.
9) 도메인 별 관행의 예
9. 1 REST: 커서 페이지 매김 (계약 불변)
응답에는 '항목 []', '다음 _ 커서' (nullable), '한계', 'total' (옵션) 이 포함됩니다.
불변량: 'len (항목) 계수', 동일한 '커서' → demempotent 세트를 사용한 반복 호출.
'커서' 와 '페이지' 가 모두 지정된 경우 오류가 발생합니다.
9. 2 POST demopotency
계약에는 'Idempotency-Key' 헤더가 필요합니다.
불변량: 동일한 키를 가진 반복 된 쿼리는 동일한 'id '/상태를 반환합니다.
9. 3 이벤트: 주문 보장
계약의 파티션 키는 'partition _ key = user _ id' 입니다.
불변량: '시퀀스' 는 키 내에서 단조 적으로 증가합니다. 소비자는 리플레이를 처리해야합니다.
10) 계약의 보안 및 개인 정보
예제에 개인 데이터/비밀을 포함시키지 마십시오. 합성 만 가능합니다.
필수 보안 헤더 수정: '승인', 'X-Signature', 'Replay-Prevention'.
웹 후크의 경우-서명 및 응답 계약 '2xx '/retrays.
계약 테스트 기록에서 민감한 필드를 마스킹합니다.
11) 도구
Pact/Pactflow/Pact Broker-TP/메시지 계약, 호환성 매트릭스.
OpenAPI/AsyncAPI-사양 + 테스트 생성기 (Dredd, Schemathesis).
가라테/REST 확인-REST 계약의 시나리오 점검.
프로토 타입/gRPC- '마우스', '프로톨 린트', 호환성 테스트; 스트림에서 Avro/JSON/Proto에 대한 스키마 레지스트리.
GraphQL (graphql-compat), 스냅 샷 회로 테스트에 대한 적합성 테스트.
12) 공급자 검증 의사 코드 (단순화)
python def verify_contract(provider, contract):
for case in contract["cases"]:
req = build_request(case["request"])
res = provider.handle(req) # локально/контейнер assert match_status(res.status, case["response"]["status"])
assert match_headers(res.headers, case["response"].get("headers", {}))
assert match_body(res.body, case["matchers"], allow_extra_fields=True)
for neg in contract.get("error_cases", []):
res = provider.handle(build_request(neg["request"]))
assert res.status == neg["response"]["status"]
assert res.json.get("error_code") == neg["response"]["body"]["error_code"]
13) 반 패턴
"Postman 스크린 샷은 계약입니다": 버전/일반적인 매처/자동 검증 없음.
Oversnapping: 계약은 유형/패턴 → 잘못된 낙하 대신 정확한 값을 수정합니다.
다른 지역/채널에 대한 하나의 일반적인 계약: 변동성 (플래그, 지리 규칙) 을 무시합니다.
브로커/매트릭스가없는 계약: 호환되는 버전을 이해하는 것은 불가능합니다.
계약 대신 e2e에 베팅: 느리고 비싸고 불안정합니다.
음수/불변 사례가 없습니다. "녹색 트랙" 만 테스트됩니다.
14) 관찰 및 운영
중개인 + 대시 보드 "건강 계약" 으로 수출 상태.
경고: 'prod' 계약에 대한 공급자의 새로운 하락, 이벤트에서 "알 수없는 필드" 의 증가.
추적: 확인 로그의 'contraction _ id', 'version', 'decision _ id'.
15) 우울증 과정
1. 필드/엔드 포인트 (비 파괴) 를 추가하십시오.
2. 사양에서 오래된 것을 '더 이상 사용되지 않는' 것으로 표시하고 날짜를 알려주십
3. 로그/브로커별로 소비자를 추적하십 마이그레이션 가이드.
4. 스테이지에서 "그림자" 거부 (드라이 런) 를 사용한 다음 시행하십시오.
5. 제로 사용량 및 호환성 후에 삭제합니다.
16) 건축가 점검표
1. 소비자와 그 소유자가 식별 했습니까? 계약이 버전화되고 있습니까?
2. 브로커와 환경 태그가있는 호환성 매트릭스가 있습니까?
3. 계약에 네거티브 및 불변량 (관용성, 커서, 정렬) 이 포함되어 있습니까?
4. 이벤트에 대해 Schema Registry 및 호환성 모드가 구성되
5. 파이프 라인은 생산 계약 위반시 공급자의 출시를 차단합니까?
6. 억제 과정과 진화 정책이 설명되어 있습니까?
7. 계약에서 스택이 생성됩니다. 로컬 이벤트 생성기가 있습니까?
8. PD 마스킹 및 필수 안전 제목이 문서화되어 있습니까?
9. 계약에 대한 지표/경고가 연결되어 있습니다. 드리프트 보고서가 있습니까?
10. CI에서 양 당사자 (소비자 및 공급자) 가 계약을 검토합니까?
결론
계약 테스트는 상호 작용에 대한 "진실" 을 버전이있는 아티팩트로 전송하고 통합을 예측할 수 있습니다. CDC, 계약 중개인 및 제도 진화 분야는 "놀라운 놀라움" 을 관리 프로세스 (빠른 점검, 명확한 불변량 및 투명한 버전 호환성) 로 대체하고 있습니다. 이는 e2e 비용을 줄이고 릴리스 속도를 높이며 전체 플랫폼의 품질을 향상시킵니다.