HTTP API Mocking — WireMock · MockServer · Prism · MSW
HTTP API Mocking — WireMock · MockServer · Prism · MSW
에뮬레이터가 없는 외부 SaaS 가 있습니다. Kakao Login · Naver Login · 토스페이먼츠 · DuckDNS · Slack Webhook · OpenAI · Gemini, 그리고 Firebase Cloud Messaging 처럼 공식이 emulator 를 안 만든 서비스도 있습니다. 이런 외부 의존을 끊고 싶을 때 가장 단순한 길은 HTTP 응답을 흉내내는 mock 서버 를 띄우는 것입니다.
1. mock 서버에 대한 이야기
mock 서버가 하는 일은 단순합니다:
- HTTP 요청을 받습니다.
- 매칭 규칙 (URL · 메서드 · 헤더 · body) 으로 stub 을 찾습니다.
- 미리 정의한 응답 (상태코드 · 헤더 · body) 을 반환합니다.
코드 입장에서 외부 SaaS 의 base URL 만 mock 서버로 바꾸면, SDK · HTTP 클라이언트 · 인증 흐름 · 직렬화 모두 그대로 검증됩니다. 추론 정확도 같은 도메인 로직은 흉내낼 수 없지만, 호출 형식 · 통합 흐름 · 실패 경로 는 정확히 재현됩니다.
2. 도구 매트릭스
| 도구 | 시작 | 형태 | 라이선스 | 강점 | 한계 |
|---|---|---|---|---|---|
| WireMock (Java) | 2011 | 독립 서버 (Docker) | Apache 2.0 | 매칭 문법 풍부 · 시나리오 · 녹화 · admin API | JVM, ~150 MB |
| MockServer (Java) | 2014 | 독립 서버 (Docker) | Apache 2.0 | WireMock 거의 동급 · 더 풍부한 callback | 한국어 자료 부족 |
| Prism (Stoplight) | 2017 | 독립 서버 (Node) | Apache 2.0 | OpenAPI spec → 자동 mock | spec 정확성 의존 |
| MSW | 2018 | 브라우저/Node 프로세스 | MIT | 코드 안에서 정의 · React 테스트 자연 결합 | 외부 프로세스 검증 불가 |
선택의 결:
- 한 컨테이너로 띄워서 여러 서비스 공유 → WireMock (한국어 자료 가장 많음).
- OpenAPI 스펙이 정확히 있고 자동화 → Prism.
- 프런트 단위 테스트만 → MSW.
- 동적 응답 시나리오 (state machine) → WireMock Scenarios.
3. WireMock 띄우기
services:
wiremock:
image: wiremock/wiremock:3.x
ports:
- "8089:8080"
command:
- --port=8080
- --global-response-templating
- --verbose
volumes:
- ./mappings:/home/wiremock/mappings:ro
- ./__files:/home/wiremock/__files:ro
mappings/ 의 모든 JSON 이 시작 시 로드. __files/ 는 큰 응답 body 를 별 파일로.
4. Stub JSON
// mappings/kakao-login.json
{
"request": {
"method": "POST",
"urlPath": "/oauth/token"
},
"response": {
"status": 200,
"headers": { "Content-Type": "application/json;charset=UTF-8" },
"jsonBody": {
"access_token": "stub-{{randomValue length=16 type='ALPHANUMERIC'}}",
"token_type": "bearer",
"expires_in": 21599
},
"transformers": ["response-template"]
}
}
transformers: ["response-template"] 가 있어야 {{randomValue ...}} 같은 템플릿이 동작.
5. 매칭 · 응답 키
매칭:
| 키 | 의미 |
|---|---|
method |
GET · POST 등 |
url |
정확 매치 |
urlPath |
쿼리 무시 매치 |
urlPathPattern |
정규식 (FCM 의 /v1/projects/[^/]+/messages:send) |
headers |
Authorization · Content-Type |
bodyPatterns |
body JSON path · 정규식 |
queryParameters |
쿼리 파라미터 |
응답:
| 키 | 의미 |
|---|---|
status |
HTTP 상태 코드 |
headers |
응답 헤더 |
jsonBody |
JSON body |
body |
텍스트 body |
bodyFileName |
__files/ 의 파일 참조 |
fixedDelayMilliseconds |
인위적 지연 — 타임아웃 시뮬레이션 |
fault |
연결 끊김 · malformed 응답 — 회복성 테스트 |
6. Scenarios — 상태 머신
같은 endpoint 가 호출 차수마다 다르게 응답해야 할 때.
{
"scenarioName": "토큰 갱신",
"requiredScenarioState": "Started",
"newScenarioState": "RefreshNeeded"
}
OAuth refresh · 리토큰 만료 같은 시나리오 재현.
7. 호출 검증 — requests API
# 어떤 요청이 들어왔는지
curl http://localhost:8089/__admin/requests
# 특정 stub 호출 횟수
curl -X POST http://localhost:8089/__admin/requests/count \
-H 'Content-Type: application/json' \
-d '{"method":"POST","url":"/oauth/token"}'
# 매칭 안 된 요청 — stub 누락 진단
curl http://localhost:8089/__admin/requests/unmatched
CI 에서 "FCM 송신이 정확히 N 번 호출됐는가" · "Kakao 로그인이 한 번도 호출되지 않았는가" 같은 검증이 가능합니다. mock 서버는 stub 만이 아니라 verifier — 이게 mock 서버가 일반 reverse proxy 와 다른 핵심.
8. Recording — 운영 응답 그대로 캡처
docker run -p 8089:8080 wiremock/wiremock \
--proxy-all="https://kapi.kakao.com" --record-mappings
이 모드에서 코드를 운영 endpoint 처럼 호출하면 WireMock 이 응답을 캡처해 mappings/ 에 자동으로 떨어뜨립니다. 외부 API 의 정확한 응답 형식을 미리 모를 때 가장 빠른 길.
9. 한계
mock 은 mock 일 뿐 — 외부 서비스가 실제로 변경된 응답을 주면 stub 은 stale. 정기적으로 운영 호출 한 번씩 해서 확인.
추론·계산 정확도는 못 흉내냄 — Gemini 의 답변, OpenAI 의 임베딩 의미, 결제 모듈의 PG 응답 분기는 stub 이 더미라 도메인 로직 회귀를 못 잡습니다.
인증 흐름이 정확하지 않을 수 있음 — JWT 서명 검증 · OAuth 리프레시 · 서명 헤더 등은 stub 이 단순 200 OK 면 우회됩니다. 운영 환경에서 한 번은 통과.
HTTPS 인증서 — WireMock 도 HTTPS 지원하지만 사설 CA 라 클라이언트가 신뢰 안 함. 테스트 한정 rejectUnauthorized: false 우회.
10. CI 통합 패턴
- run: docker compose up -d wiremock
- run: |
until curl -sf http://localhost:8089/__admin/health; do sleep 1; done
- run: pnpm test
- run: |
# 호출 횟수 검증
count=$(curl -s -X POST http://localhost:8089/__admin/requests/count \
-H 'Content-Type: application/json' \
-d '{"method":"POST","url":"/v1/projects/test/messages:send"}' \
| jq .count)
[[ "$count" -ge 1 ]] || { echo "FCM 송신 호출 누락"; exit 1; }
하고픈 말
HTTP API mock 의 가치는 호출 형식 · 통합 흐름 · 실패 경로 검증이지, 도메인 정확도는 아닙니다. "에뮬레이터가 있으면 에뮬레이터, 없으면 mock" 의 구도가 자연스럽습니다 — Firebase Auth/Firestore 는 emulator, FCM · Kakao · Naver · Gemini 는 mock.
Next
- (cloud 끝)
WireMock 공식 · MockServer · Prism · MSW · WireMock standalone 을 참고합니다.