다음과 같은 다양한 이유로 MSW를 도입해 보기로 하였습니다.
MSW 도입 시
npm install nsw --save-dev
mocks를 관리할 때 엄격한 규칙은 없지만 API mocking 관련 모듈은 단일 디렉터리에서 관리하는 게 좋다고 합니다. 따라서 src 바로 아래에 mocks 디렉터리를 생성해주겠습니다.
mkdir src/mocks
이제 request를 처리할 handler를 생성합니다.
touch src/mocks/handler.ts
☑️ REST API, GraphQL API 유형이 있는데 이 중 REST API를 선택해 사용하겠습니다. 만약 GraphQL API를 통해 mocking을 하려면 여기를 클릭하시면 됩니다.
import { rest } from "msw";export const handlers = [rest.get("/mock/members/email-exists", async (req, res, ctx) => {const data = await ctx.fetch(req);return res(ctx.json({...data,status: "OK",body: {duplicated: true,},}));}),];```
브라우저와 노드 환경 간의 handler를 공유할 수 있으나, Service Worker는 Node에서 실행할 수 없기 때문에 환경에 따라 다른 통합 과정을 거쳐야 합니다. mocks를 브라우저에서 실행할 것이므로 브라우저 방법을 따릅니다. 만약 Node 환경에서 실행하려면 여기를 클릭해서 참고하세요.
public 디렉터리에 mockServiceWorker.js를 설치해 주기 위해 CLI로 다음을 실행합니다.
npx msw init public/ --save
touch src/mocks/browser.js
아까 생성한 src/mocks
의 디렉터리에 browser.ts
파일을 생성합니다.
import { setupWorker } from 'msw'import { handlers } from './handlers'export const worker = setupWorker(...handlers)`
위에서 정의해 둔 mock을 런타임 환경에서 실행해야 하므로 app에 import 해야 합니다. 이 때 mocking은 개발 지향적이므로, 현재 조건에 따라 App.tsx
에 조건부로 src/mocks/browser.ts
를 가져올 수 있게 처리하는 것이 좋습니다.
import React from "react";import ReactDOM from "react-dom";import App from "./App";if (process.env.NODE_ENV === "development") {const { worker } = require("./mocks/browser");worker.start();}ReactDOM.createRoot(document.getElementById("root")!).render(<React.StrictMode><Router /></React.StrictMode>);
👀 이 때 Mock Service Worker를 프로덕션에 포함시키는 것은 공식 문서에서도 권장하지 않는 방법입니다. 이로 인해 사용자 경험이 왜곡될 수 있기 때문입니다.
여기까지 설정을 잘 했다면 다음과 같이 MSW의 mocking이 가능하다는 문구를 Console창에서 확인할 수 있습니다.
[MSW] Mocking enabled
이제까지의 설치를 바탕으로 MSW는 브라우저 환경에서 handler에 정의된 request 처리한 fetch를 Service Worder에 등록합니다. Service Worker는 사용자의 request가 발생하면, request를 가로채 MSW에 전달하고 우리가 작성한 handler에 정의된 mocking response를 우리에게 전달합니다.
Service Worker가 실행되었는지 확인하려면 개발자 도구의 Application 탭의 Service workers에서 실행 중인 것을 확인할 수 있습니다.
이제 fetch를 하면 개발자 도구의 Network 탭에서 MSW에서 request를 가로채 우리가 작성한 response를 전달하는 것을 확인할 수 있습니다.
백엔드의 API 기능 명세와 비슷하게 response를 작성한다면 이제 백엔드의 API를 기다리지 않고 프론트에서 먼저 작업이 가능합니다. API가 완성된 시점에 handler만 교체해 주면 되니 실제 API 연동시 더 빠르게 작업이 가능합니다. 물론 MSW를 통해서 프론트에서 테스트도 가능합니다.
MSW를 도입한 가장 큰 이유는 백엔드의 의존도를 조금 줄여 애자일하게 작업하고 싶었습니다. MSW를 도입하고 위의 도입 이유를 모두 충족할 수 있었습니다. 그 중 의외로 좋았던 것은 미리 mock data를 만들어 보면서 response 구조에 대해 고민해보고 백엔드와 협업한 경험입니다. 프론트에서 효율적인 response 구조를 백엔드와 데이터 형태를 보고 조율을 하니 개발 경험이 매우 긍정적으로 남았습니다. 앞으로는 프론트에서 MSW를 통합 테스트를 하는 데에 사용해보고자 합니다.