3. MSW를 활용한 mock API 테스트
본 라이브러리를 학습하기 위해 코딩앙마님의 강의를 수강하였습니다.
3.1 Mock Serveice Worker 다운 및 세팅
Node - Getting Started
Mock Service Worker Docs
mswjs.io
Install - Getting Started
Mock Service Worker Docs
mswjs.io
위 사이트를 방문해서 install 및 integrate를 해준다.
src/mock 안에 handlers.js + server.js를 생성하면 된다.
그 후 src/setupTests(생성X).js의 내용을 다음과 같이 수정한다.
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
import '@testing-library/jest-dom';
// src/setupTests.js
import { server } from './mock/server.js';
// Establish API mocking before all tests.
beforeAll(() => server.listen());
// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers());
// Clean up after the tests are finished.
afterAll(() => server.close());
3.2 api 이용해서 테스트
실전이 아닌 연습용으로 무료 api를 사용했다.
https://jsonplaceholder.typicode.com/
JSONPlaceholder - Free Fake REST API
{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. Serving ~2 billion requests each month.
jsonplaceholder.typicode.com
src/mock/handlers.js를 다음과 같이 수정한다.
import { rest } from 'msw';
export const handlers = [
// Match a GET request to a third-party server.
return res(
ctx.status(200), //500 : 서버 에러
ctx.json([
{
id: 1,
title: '청소',
completed: true,
},
{
id: 2,
title: '설거지',
completed: false,
},
{
id: 3,
title: '빨래',
completed: true,
},
])
);
}),
];
src/component/TodoList.js를 다음과 같이 작성한다.
import { useEffect, useState } from 'react';
export default function TodoList() {
const [todoList, setTodoList] = useState([]);
const [errorMsg, setErrorMsg] = useState('');
useEffect(() => {
.then((response) => response.json())
.then((json) => setTodoList(json))
.catch(() => {
setErrorMsg('에러 발생... ');
});
}, []);
return (
<>
<h1>TodoList</h1>
{errorMsg ? (
<h5>{errorMsg}</h5>
) : (
<ul>
{todoList.map((todo) => (
<li
key={todo.id}
style={{
textDecoration: todo.completed ? 'line-through' : undefined,
}}
>
{todo.title}
</li>
))}
</ul>
)}
</>
);
}
src/component/TodoList.test.js를 다음과 같이 작성한다.
import { render, screen } from '@testing-library/react';
import TodoList from './TodoList';
import { rest } from 'msw';
import { server } from '../mock/server';
describe('TodoList', () => {
test('TodoList 라는 제목이 있다.', () => {
render(<TodoList />);
const titleElement = screen.getByRole('heading', {
name: 'TodoList',
});
// const titleElement = screen.getByText("TodoList")
expect(titleElement).toBeInTheDocument();
});
test('리스트 3개가 잘 나온다.', async () => {
render(<TodoList />);
const listElement = await screen.findAllByRole('listitem');
expect(listElement).toHaveLength(3);
});
});
프로미스로 반환되므로, await screen.findAllByRole('listitem') 을 사용해야한다.
3.3 mock 서버 이용하여 에러 생성
방법 1. 모든 api 서버 오류 처리
src/mock/handlers.js를 다음과 같이 수정한다.
import { rest } from 'msw';
export const handlers = [
// Match a GET request to a third-party server.
return res(
ctx.status(500),
);
}),
];
하지만 , 이렇게 수정하면 모든 코드가 에러 처리되므로 테스트하기에 적절하지 않을 수 있다.
방법 2. test 안에서 서버 오류 처리
import { render, screen } from '@testing-library/react';
import TodoList from './TodoList';
import { rest } from 'msw';
import { server } from '../mock/server';
test('에러가 났을 때 에러 메세지를 보여준다.', async () => {
server.use(
rest.get(
(req, res, ctx) => {
return res(
ctx.status(500) //500 : 서버 에러
);
}
)
);
render(<TodoList />);
const errorElement = await screen.findByText('에러 발생...');
expect(errorElement).toBeInTheDocument();
});
각 test 내부에서만 server 오류를 일으켜 각각 테스트에 적합하다.
src/setupTests.js의 afterEach(() => server.resetHandlers()); 때문이다.