MSW(Mock Service Worker) 모킹하기

최형용·2023년 3월 13일
0

MSW(Mock Service Worker)란?

MSW는 Mock Service Worker로 서비스 워커를 이용하여 API를 모킹하는 라이브러리입니다. 네트워크 요청을 가로채도록 설계된 Service Worker API를 활용하기 때문에 목 사용 여부 관계 없이 동일한 애플리케이션 동작을 보장합니다.
MSW를 여러가지 용도로 활용할 수 있지만 대표적으로 두가지 사례를 생각해볼 수 있습니다
첫번째는 백앤드 API 개발과 프런트앤드 UI 개발이 동시에 진행되야하는 경우, 백앤드 API 구현이 완료될 때까지 프런트앤드 팀에서 임시로 사용하기 위한 가짜(mock) API를 서비스 워커로 돌리기 위해서이고, 두번째는 테스트를 실행 시 실제 백앤드 API에 네트워크 호출을 하는 대신에 훨씬 빠르고 안정적인 가짜 API 서버를 구축하기 위해서 입니다.

MSW github보고 사용해보기

  • example 폴더에서 rest-react 폴더를 실행해보자
//index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { LoginForm } from './LoginForm'

// Start the mocking conditionally.
if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}

ReactDOM.render(<LoginForm />, document.getElementById('root'))
//browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'

export const worker = setupWorker(...handlers)
//handler.js
import { rest } from 'msw'

export const handlers = [
  rest.post('/login', (req, res, ctx) => {
    const { username } = req.body

    return res(
      ctx.json({
        id: 'f79e82e8-c34a-4dc7-a49e-9fadc0979fda',
        username,
        firstName: 'John',
        lastName: 'Maverick',
      })
    )
  }),
]

React-App에 적용해보기

파일구조

초기세팅

//react app 설치
npx create-react-app fetch

//msw 설치
npm install msw --save-dev

//공용디렉토리에 CLI실행
npx msw init public --save
//app
import './App.css';
import TestMocking from './components/TestMocking';

function App() {
  return (
    <div className="App">
     <TestMocking/>
    </div>
  );
}

export default App;
//index
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

---------
//추가
if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}
---------
  
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Mocking을 사용하여 데이터 바인딩

// component/TestMocking.jsx
import React, { useState } from 'react';


const Item = ({name, age}) => {
    return (
        <li>
            name:{name} / age:{age}
        </li>
    )
}

const TestMocking = () => {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null)

    const handleClick = () =>{
        fetch('data')
        .then((response)=>{
            return response.json();
        })
        .then((json)=>{
            setData(json.data)
        })
        .catch((error)=>{
            setError(`Something Wrong: ${error}`)
        })
    }

    const handleClick2 = () => {
        fetch('login').then((response) =>{
            return response.json()
        })
        .then((json)=>{
            console.log(JSON.stringify(json))
        })
    }

    if(error){
        return <p>{error}</p>
    }

    return (
        <div>
            <button onClick={handleClick}>데이터 가져오기</button>
            <button onClick={handleClick2}>데이터 가져오기2</button>
            {data && (
                <ul>
                    {data.people.map((person)=>(
                        <Item 
                        key={`${person.name}-${person.age}`}
                        name={person.name}
                        age={person.age}
                        />
                    ))}
                </ul>
            )}
        </div>
    );
};

export default TestMocking;
// mocks/handlers.js
import {rest} from 'msw';

export const handlers = [
    rest.get('/login', async(req,res,ctx)=>{
        return res(
            ctx.json({
              id: 'f79e82e8-c34a-4dc7-a49e-9fadc0979fda',
              firstName: 'John',
              lastName: 'Maverick',
            })
          )
    }),
    rest.get('/data',async(req,res,ctx) =>{ 
        return res(
            ctx.json({
                    "data": {
                        "people" :
                        [
                            {
                                "name": "jimmy",
                                "age": 135
                            },
                            {
                                "name": "timmy",
                                "age": 13
                            },
                            {
                                "name": "cindy",
                                "age": 15
                            },
                            {
                                "name": "judy",
                                "age": 25
                            },
                            {
                                "name": "marry",
                                "age": 64
                            },
                            {
                                "name": "tommy",
                                "age": 109
                            }
                        ]
                    }
            })
        )
    })


]


Query parameters

  • Query params를 통해 id값을 가져올 수 있다.
// components/TestMocking.jsx
...
const TestMocking = () => {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null)

    const handleClick = () =>{
        fetch('data?id=123')
        .then((response)=>{
            return response.json();
        })
        .then((json)=>{
            setData(json.data)
        })
        .catch((error)=>{
            setError(`Something Wrong: ${error}`)
        })
    }
...
// mocks/handlers.js
...
rest.get('/data',async(req,res,ctx) =>{ 
        const data = req.url.searchParams.get('id')
        return res(
            ctx.json({
              "data": {
                        "people" :
                        [
                            {
                                "name": data,
                                "age": 135
                            },
                            {
...
profile
꾸준한 개발자가 되고 싶습니다

0개의 댓글