본문 바로가기
SPA/React

[React] MSW로 API Mocking 하기 (2) - Browser 환경에서 사용하기

by J4J 2023. 10. 9.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 MSW API Mocking 하기 두 번째인 Browser 환경에서 사용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

이전 글

 

[React] MSW로 API Mocking 하기 (1) - MSW란?

 

 

반응형

 

 

Browser 환경이란?

 

MSW에서는 Browser, Node 총 2개의 환경을 제공해 줍니다.

 

여기서 Browser 환경은 말 그대로 Browser에 접속했을 때 발생되는 API 처리를 Mocking 해주는 것을 의미합니다.

 

쉽게 접근할 수 있는 것은 React를 이용하여 서버를 실행한 뒤 브라우저를 통해 실행된 서버에서 접속했을 때 요청되는 API들을 Mocking 해준다고 생각하면 됩니다.

 

 

 

Browser 환경에서 MSW를 사용하게 되면 실제 API가 개발이 되지 않았거나 또는 로컬 환경에서 API 호출에 대한 테스트를 진행할 때 원활하게 수행할 수 있도록 도와줍니다.

 

또한 실제 호출되어야 하는 API 관련 소스 코드의 변경 없이도 브라우저 환경에서 문제없이 동작하기 때문에 효과적으로 여러 상황에서 테스트하기에 적합하다고 말할 수 있습니다.

 

 

 

 

설정 방법

 

[ 1. public directory에 msw 초기 설정 ]

 

$ npx msw init {public directory} --save // ex) npx msw init public/ --save

 

 

 

해당 설정은 public 경로를 기반으로 msw에서 자체적으로 설정을 진행해 줍니다.

 

정상적으로 실행이 된다면 public 경로 아래에 mockServiceWorker.js 파일이 생성된 것을 확인할 수 있습니다.

 

msw 초기 설정 결과

 

 

 

[ 2. 패키지 설치 ]

 

$ npm install -D msw

 

 

 

[ 3. handler 및 worker 설정 ]

 

먼저 handler에는 특정 API 호출을 하게 될 경우 어떤 결괏값을 전달해 줄지에 대한 mocking 처리를 정의해 주면 됩니다.

 

예를 들어 사람들의 이름들을 조회하는 API를 호출하게 된다면 다음과 같이 handler를 정의해 줄 수 있습니다.

 

// src/mocks/handlers/person-handler.ts
import { rest } from 'msw';

export const personHandlers = [
    // GET method인 /get-names를 호출하면 다음과 같이 response가 되도록 mocking 정의
    rest.get('/get-names', (req, res, ctx) => {
        const names = ['jimi', 'john', 'scott', 'queen']

        return res(
            ctx.status(200),
            ctx.json(names),
        )
    })
]


// src/mocks/handlers/index.ts
import { personHandlers } from "./person-handler";

// 여러 handler를 한 곳에 묶어서 return
export const handlers = [
    ...personHandlers
]

 

 

 

handler 정의가 끝났다면 handler를 활용하여 msw의 worker 설정을 다음과 같이 해줄 수 있습니다.

 

// src/mocks/browser.ts
import { setupWorker } from "msw";
import { handlers } from "./handlers";

export const worker = setupWorker(...handlers);

 

 

 

 

[ 4. worker 등록 ]

 

일반적으로 msw를 사용하는 경우는 운영 환경에서 동작될 수도 있지만 거의 그럴 경우는 없을 것이고 대부분 로컬 환경이나 개발 환경이 될 것입니다.

 

그래서 index 파일 또는 main 파일에 다음과 같이 환경이 맞을 때만 msw가 동작될 수 있도록 위에서 정의한 worker를 등록해 주시면 됩니다.

 

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import { worker } from "./mocks/browser";

if(process.env.NODE_ENV === 'development') { // 개발에서만 msw 동작
  worker.start();
}

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

 

 

 

 

테스트

 

위에서 설정한 API를 호출해 보는 테스트 페이지를 다음과 같이 만들어 보겠습니다.

 

import axios from "axios";
import { useEffect, useState } from "react";

export default function App() {
  const [personNames, setPersonNames] = useState<string[]>([]);

  async function apiGetNames() {
    const res = await axios.get('/get-names');
    if(res.data) {
      setPersonNames(res.data);
    }
  }

  useEffect(() => {
    apiGetNames();
  }, [])

  return (
    <div>
      <div>
        <h2>사람들의 이름을 호출해보겠습니다 !</h2>
      </div>

      <div>
        {personNames.map((personName, index) => (
          <p key={personName}>{index+1}번째 이름은 {personName}입니다.</p>
        ))}
      </div>
    </div>
  )
}

 

 

 

그리고 서버를 실행하여 브라우저에 접속해 보면 다음과 같이 msw에 의해 mocking 된 API가 전달된 것을 확인할 수 있고, console 창에서 msw에 의해 API가 호출된 것도 볼 수 있습니다.

 

browser msw 테스트 결과

 

 

 

 

상황 별 다른 Mocking 처리 (Override)

 

위의 설정을 생각해 보면 /get-names에 대한 API 호출의 mocking 처리는 개발 환경에서 어느 페이지든 동일한 결과를 불러옵니다.

 

하지만 개발을 하다 보면 아무리 mocking 처리를 하더라도 상황에 따라 다른 결과를 받을 수 있는 상황이 발생될 수 있습니다.

 

이런 상황들이 생길 경우 다음과 같이 override를 수행하여 페이지마다 다른 결과를 만들어 주시면 됩니다.

 

 

 

[ 1. 페이지에 override handler 정의 ]

 

위에서 작성한 소스 코드에서 페이지 쪽만 다음과 같이 변경해 볼 수 있습니다.

 

import axios from "axios";
import { rest } from "msw";
import { useEffect, useState } from "react";
import { worker } from "./mocks/browser";

export default function App() {
  const [personNames, setPersonNames] = useState<string[]>([]);

  function mswConfig() {
    worker.use(
      // GET method인 /get-names를 해당 페이지에서만 따로 활용
      rest.get('/get-names', (req, res, ctx) => {
        const names = ['app-jimi', 'app-john', 'app-scott', 'app-queen']

        return res(
            ctx.status(200),
            ctx.json(names),
        )
      })
    )
  }

  async function apiGetNames() {
    const res = await axios.get('/get-names');
    if(res.data) {
      setPersonNames(res.data);
    }
  }

  useEffect(() => {
    mswConfig();
    apiGetNames();
  }, [])

  return (
    <div>
      <div>
        <h2>사람들의 이름을 호출해보겠습니다 !</h2>
      </div>

      <div>
        {personNames.map((personName, index) => (
          <p key={personName}>{index+1}번째 이름은 {personName}입니다.</p>
        ))}
      </div>
    </div>
  )
}

 

 

 

[ 2. 테스트 ]

 

코드를 위와 같이 수정하고 다시 브라우저에 접속해 보면 동일한 페이지임에도 불구하고 이전과 다른 API response 값을 확인할 수 있습니다.

 

msw override 결과

 

 

 

 

 

 

 

 

이상으로 MSW API Mocking 하기 두 번째인 Browser 환경에서 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글