MSW 완벽 가이드 | API Mocking·Service Worker·테스트·실전 활용
이 글의 핵심
MSW로 API Mocking을 구현하는 완벽 가이드. Request Handlers, Response Resolver, Browser/Node 통합, Testing까지 실전 예제로 정리. Start now.
이 글의 핵심
MSW로 API Mocking을 구현하는 완벽 가이드입니다. Request Handlers, Response Resolver, Browser/Node 통합, Testing까지 실전 예제로 정리했습니다.
실무 경험 공유: 백엔드 API 없이 프론트엔드 개발을 진행하면서, MSW로 개발 속도가 2배 향상된 경험을 공유합니다.
들어가며: “백엔드 API를 기다려야 해요”
실무에서 마주치는 문제들
백엔드 개발이 늦어요
API를 기다려야 합니다. MSW로 Mock API를 만듭니다. 테스트에서 실제 API를 호출해요
느리고 불안정합니다. MSW로 Mock 응답을 반환합니다. 에러 상황 테스트가 어려워요
실제로 에러를 만들기 어렵습니다. MSW로 쉽게 시뮬레이션합니다.
1. MSW란?
API Mocking의 진화: Stub → Interceptor → Service Worker
전통적인 API Mocking 방식은 두 가지였습니다:
-
라이브러리 Stub (axios-mock-adapter, nock)
- axios·fetch를 직접 가로채서 Mock 응답 반환
- 문제: 실제 네트워크 요청이 발생하지 않음 → 개발자 도구 Network 탭에 안 보임
-
Mock Server (json-server, mirage)
- 별도 포트(
:3001)에서 Mock API 서버 실행 - 문제: 프로덕션 코드(
/api/users)와 다른 URL(localhost:3001/users) 사용
- 별도 포트(
MSW(Mock Service Worker, 2019)는 Service Worker API로 이 문제를 해결했습니다:
- 네트워크 레벨에서 intercept → 실제 HTTP 요청이 발생
- 개발자 도구에 보임 → Network 탭에서 200 OK 확인 가능
- 프로덕션 URL 그대로 →
/api/users그대로 사용
Service Worker API: 브라우저의 네트워크 프록시
Service Worker는 원래 PWA(Progressive Web App)를 위해 만들어진 W3C 표준입니다. 브라우저와 서버 사이에서 프록시 역할을 합니다.
브라우저 (fetch('/api/users'))
↓
Service Worker (MSW가 여기서 intercept)
↓ (Mock이면 여기서 응답 반환)
↓ (Mock 없으면 실제 네트워크로 통과)
실제 서버
MSW의 동작:
npx msw init public/→mockServiceWorker.js생성- 브라우저가 이 Worker 등록
- 모든
fetch()요청이 Worker를 거침 - MSW가 핸들러에 매칭되는지 확인
- 매칭되면 Mock 응답, 아니면 실제 네트워크로 통과
MSW vs 기존 Mocking 방식
| 측면 | MSW | axios-mock-adapter | json-server |
|---|---|---|---|
| 동작 위치 | Service Worker (네트워크) | 라이브러리 내부 | 별도 서버 |
| Network 탭 | ✅ 보임 | ❌ 안 보임 | ✅ 보임 |
| URL | 프로덕션과 동일 | 프로덕션과 동일 | 다른 포트 |
| 브라우저 | ✅ | ✅ | ✅ |
| Node(테스트) | ✅ | ✅ | ❌ (별도 실행 필요) |
| 코드 수정 | 불필요 | 불필요 | URL 변경 필요 |
핵심 특징
MSW (Mock Service Worker)는 Service Worker 기반 API Mocking 라이브러리입니다. 주요 장점
- Service Worker: 네트워크 레벨 Mocking (실제 HTTP 요청 발생)
- 브라우저 + Node: 개발(Service Worker) + 테스트(Node.js Interceptor)
- 타입 안전: TypeScript 지원 (Request·Response 타입)
- 실제와 동일: 개발자 도구 Network 탭에서 확인 가능
- Zero Config: 프로덕션 코드 수정 불필요
사용 시나리오
- 백엔드 API 개발 전 프론트엔드 개발
- E2E 테스트에서 외부 API 의존성 제거
- 에러·타임아웃·로딩 상태 시뮬레이션
- 다양한 응답 케이스 빠르게 테스트
2. 설치 및 설정
설치
npm install -D msw
Service Worker 생성
npx msw init public/ --save
3. Handlers 정의
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: 'John', email: 'john@example.com' },
{ id: 2, name: 'Jane', email: 'jane@example.com' },
]);
}),
http.post('/api/users', async ({ request }) => {
const newUser = await request.json();
return HttpResponse.json(
{ id: 3, ...newUser },
{ status: 201 }
);
}),
http.delete('/api/users/:id', ({ params }) => {
return HttpResponse.json(
{ success: true },
{ status: 200 }
);
}),
];
4. 브라우저 통합
// src/mocks/browser.ts
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);
// src/main.tsx
import { worker } from './mocks/browser';
if (process.env.NODE_ENV === 'development') {
worker.start();
}
5. Node 통합 (테스트)
// src/mocks/server.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
// src/setupTests.ts
import { server } from './mocks/server';
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
6. Response Resolver
동적 응답
http.get('/api/users/:id', ({ params }) => {
const { id } = params;
if (id === '1') {
return HttpResponse.json({ id: 1, name: 'John' });
}
return HttpResponse.json(
{ error: 'User not found' },
{ status: 404 }
);
});
지연
import { delay } from 'msw';
http.get('/api/users', async () => {
await delay(2000);
return HttpResponse.json([]);
});
7. 에러 시뮬레이션
http.get('/api/users', () => {
return HttpResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
});
http.get('/api/users', () => {
return HttpResponse.error();
});
8. 테스트에서 사용
// src/components/UserList.test.tsx
import { render, screen } from '@testing-library/react';
import { server } from '../mocks/server';
import { http, HttpResponse } from 'msw';
import UserList from './UserList';
test('loads and displays users', async () => {
render(<UserList />);
expect(await screen.findByText('John')).toBeInTheDocument();
expect(screen.getByText('Jane')).toBeInTheDocument();
});
test('handles error', async () => {
server.use(
http.get('/api/users', () => {
return HttpResponse.json(
{ error: 'Failed to fetch' },
{ status: 500 }
);
})
);
render(<UserList />);
expect(await screen.findByText('Failed to fetch')).toBeInTheDocument();
});
9. GraphQL Mocking
import { graphql, HttpResponse } from 'msw';
const handlers = [
graphql.query('GetUser', ({ variables }) => {
return HttpResponse.json({
data: {
user: {
id: variables.id,
name: 'John',
},
},
});
}),
graphql.mutation('CreateUser', async ({ variables }) => {
return HttpResponse.json({
data: {
createUser: {
id: 3,
...variables.input,
},
},
});
}),
];
정리 및 체크리스트
핵심 요약
- MSW: Service Worker 기반 API Mocking
- 브라우저 + Node: 개발 + 테스트
- 타입 안전: TypeScript 지원
- 실제와 동일: 실제 HTTP 요청
- 에러 시뮬레이션: 쉬운 에러 테스트
- GraphQL: GraphQL Mocking
구현 체크리스트
- MSW 설치
- Handlers 정의
- 브라우저 통합
- Node 통합
- Response Resolver 구현
- 에러 시뮬레이션
- 테스트 작성
- GraphQL Mocking
같이 보면 좋은 글
이 글에서 다루는 키워드
MSW, Mock Service Worker, API Mocking, Testing, Service Worker, Frontend
자주 묻는 질문 (FAQ)
Q. 프로덕션에 포함되나요?
A. 아니요, 개발/테스트 환경에서만 사용됩니다.
Q. 실제 API 호출을 가로채나요?
A. 네, Service Worker를 통해 네트워크 레벨에서 가로챕니다.
Q. GraphQL도 지원하나요?
A. 네, GraphQL Query/Mutation을 모두 지원합니다.
Q. 프로덕션에서 사용해도 되나요?
A. 네, 많은 기업에서 개발/테스트 도구로 사용하고 있습니다.