(React) Vitest와 MSW를 이용한 API 모킹 테스트

kidstone·2024년 8월 18일
0

외개인 프로젝트

목록 보기
4/10

문제 상황

앞서 포스팅에서 봤듯이, react 환경에서 vitest 테스트 라이브러리를 도입하여 테스트 코드를 작성하였다. 이제는 msw를 이용하여 api를 백엔드 없이 모킹을 이용하여 테스트하는 방법을 작성해보겠다. 항상 프론트엔드 UI를 개발할 때 api나 데이터가 준비되어 있지 않은 상황이 있을 수 있다. 그런 상황에서는 더미 데이터를 만들어 사용하는 방법도 있겠지만, 실제로 네트워크 요청을 하는 것과 비슷한 MSW를 도입하는 것이 더 좋은 방법이라고 판단하였다.

MSW

MSW는 API 요청을 모킹(mocking)하여 테스트 환경을 구축할 수 있도록 도와주는 라이브러리다. 실제 네트워크 요청 대신 가짜 응답을 제공함으로써, 외부 API에 의존하지 않고도 애플리케이션을 테스트할 수 있다.

내가 MSW를 도입하게 된 이유(장점)

  1. 네트워크 요청 모킹
    MSW는 브라우저의 Fetch API와 XMLHttpRequest를 가로채어, 실제 서버와의 통신을 대신하여 가짜 응답을 제공한다. 이를 통해 외부 API에 의존하지 않고도 애플리케이션을 개발하고 테스트할 수 있다.

  2. 개발 및 테스트 환경 지원
    MSW는 개발과 테스트 두 가지 환경 모두에서 활용할 수 있다. 개발 중에도 API 요청을 모킹하여, 실제 API가 준비되지 않았거나 응답이 느린 상황에서도 개발을 진행할 수 있다.

  3. 사용자 정의 응답
    MSW는 다양한 상황에 맞춘 사용자 정의 응답을 설정할 수 있다. 요청의 URL, HTTP 메서드, 요청 헤더 및 본문에 따라 반환할 응답을 세밀하게 조정할 수 있어, 복잡한 테스트 시나리오를 쉽게 구현할 수 있다.

  4. 테스트 자동화 통합
    MSW는 Jest, Vitest와 같은 테스트 프레임워크와 쉽게 통합할 수 있어, 테스트 코드 내에서 API 모킹을 손쉽게 설정하고 활용할 수 있다. 이를 통해 자동화된 테스트 환경을 구축할 수 있다.

설치

npm install msw --save-dev

혹은

yarn add msw --dev

msw 초기화

MSW를 사용하기 위해 핸들러와 서비스 워커를 설정해야 한다. 나는 다음과 같은 파일 구조를 택했다.

/src
├── mocks
	├── data
       	└── data.js
	├── browser.js
    ├── handlers.js
  	├── server.js
    └── node.js

핸들러 정의 (handlers.js)

모킹할 API 요청을 정의한다. 예를 들어, 간단한 GET 요청을 모킹하는 핸들러를 작성할 수 있다.

import { http, HttpResponse } from 'msw'
import { matchingPostsData } from './api/data/matchingPostsData'

export const handlers = [
  //룸메이트 매칭글 전체 조회
  http.get('/api/v1/matchingposts', () => {
    return HttpResponse.json(matchingPostsData)
  }),
  //베스트 룸메이트 조회
  http.get('/api/v1/best-roommate-matchingposts', () => {
    return HttpResponse.json(matchingPostsData)
  }),
  //내가 올린 매칭글 조회
  http.get('/api/v1/my-matchingposts', () => {
    return HttpResponse.json(matchingPostsData)
  }),
  ...
  
]```

### 서비스 워커 설정 (browser.js)
서비스 워커를 설정하여 정의된 핸들러에 따라 api 호출을 가로채고 응답을 반환한다. 클라이언트 측의 네트워크 요청을 모킹하고, 개발 및 테스트 환경에서의 일관성을 확보할 수 있다. 
```javascript
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'

export const worker = setupWorker(...handlers)

서버 설정 (node.js)

핸들러를 사용하여 MSW 서버를 설정한다.
setupServer는 MSW 라이브러리가 Node.js 환경에서 테스트를 위한 Mock Service Worker 서버를 설정하는 데 사용되는 함수이다. API 요청을 모킹하고, 테스트 중에 필요한 핸들러를 등록하는 데 매우 유용하다.

import { setupServer } from 'msw/node';
import { handlers } from './handlers';

// 설정한 핸들러를 사용하여 MSW 서버 생성
export const server = setupServer(...handlers);

서비스 워커 등록

프로젝트의 진입점에서 서비스 워커를 등록한다. 보통 index.js 또는 App.js 파일에서 수행한다.

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

async function enableMocking() {
  if (process.env.NODE_ENV !== 'development') {
    return
  }
 
  const { worker } = await import('./mocks/browser')

  return worker.start()
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

enableMocking().then(() => {
  root.render(
		<React.StrictMode>
			<App />
		</React.StrictMode>,
	);
})

나는 enabledMocking 함수를 이용하여 개발 환경일 경우에만 모킹을 활성화시켰다. 개발 환경일 경우 동적으로 browser.js를 임포팅하여 worker를 가져오고 이를 실행하도록 했다.

테스트에서 MSW 사용하기

테스트 환경에서 MSW를 사용할 때는 각 테스트가 실행되기 전에 서버를 시작하고, 테스트가 끝난 후에는 서버를 종료해야 한다.

import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { expect, test, beforeAll, afterAll, afterEach } from "vitest";
import { server } from '../../mocks/node';
import RoommateSwiperList from './RoommateSwiperList';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter } from 'react-router-dom';

// MSW 서버를 테스트 전에 시작하고, 테스트 후에 종료합니다.
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

const queryClient = new QueryClient({
  defaultOptions: { queries: { retry: false } },
});

const wrapper = ({children}) => (
  <QueryClientProvider client={queryClient}>
    <MemoryRouter>
      {children}
    </MemoryRouter>
  </QueryClientProvider>
);

describe('RoommateSwiperList api 모킹 데이터 불러오기', () => {
  test('매칭글 api 데이터 불러오기', async () => {
    render(<RoommateSwiperList type='new'/>, { wrapper });

    // findBy 메소드는 getBy + waitFor의 조합 
    const displayedData = await screen.findByText('김혁수');
    expect(displayedData).toBeInTheDocument();
  });
});

테스트 실행

모든 테스트 실행

npx test 

특정 파일 테스트 실행

npx test RoommateSwiperList.test.jsx


이로써 모킹을 이용하여 api 호출을 통해 가져온 데이터에 대한 테스트가 성공적으로 완료된 것을 확인할 수 있었다!

profile
안녕하세요. 웹 프론트엔드 개발자 앞잡이 '꼬마돌' 입니다.

0개의 댓글