Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

JustDoEat

[MSW/React] API테스트 방식을 바꿔보자 Django => MSW + msw 버르장머리 고쳐주기(2.x 버전) 본문

카테고리 없음

[MSW/React] API테스트 방식을 바꿔보자 Django => MSW + msw 버르장머리 고쳐주기(2.x 버전)

kingmusung 2024. 7. 24. 01:35

개요.

백엔드 api개발 전 api테스트도 해볼 겸, Python + Django 조합을 이용하여 api 테스트를 하고 있었다.

 

https://kingmusung.tistory.com/50

 

API 테스트를 위한 Axios <-> Django 서버 연동하기.

개요.(React + TypeScript 사용)Tr, Td 태그를 이용하여 퍼블리싱을 완료하고. 서버에서 데이터를 받아와서 화면에 출력하는 기능을 구현하는 도중. 백엔드가 API개발이 완료가 안되었다고 해서 임의로

kingmusung.tistory.com

 

물론 mock데이터를 활용해서 랜더링을 할 수는 있었지만. api통합 과정에서 오류가 한 번에 터진다면 감당하기 힘들 것 같았다. 그리고 데이터가 실시간으로 변하면서 화면에 랜더링이 잘 되는지 확인을 해보기 위해서는 api를 임의로 라도 쏴보고 싶었다.

 

결론적으로

 

Django서버로 혼자 테스트를 하기에..

 

프로젝트라는 협업을 하는데. 나 혼자만 테스트한다고 되는 일이 아니었다. 그러한 고민 끝에 MSW라이브러리를 사용하여 API테스트를 해보기로 했다.

 


하면서 겪었던 문제점은 간략하게 적고 구체적으로 안되는 문제는 맨 뒤에 적겠다.

  • msw 버전이 1.x -> 2.x 바뀜에 따라 발생하는 문제
  • 공식문서를 안보고 블로그 글부터 찾아봄
  • 이 글을 쓰는 기준으로 상위 블로그글은 전부 1.x버전 이야기. gpt 또한 학습이 안되어 있으므로 뚱딴지뚱땡이 같은 소리만 함.
    (gpt에 의존하는건 안 좋다고 매우 강력하게 생각)
  • 전에 Salary 설정을 하면서 공식문서를 보고 너무 많은 도움을 받았어서 위 방법이 안 돼서 공식문서를 열심히 봄
    (과정을 기록 안 해둔 게 후회)
  • 손 안 대고 블로그 글 보고 코 씨게 풀기 금지

사용법.

 

버전은 1.x 버전이 아닌 2.x 버전을 사용했다.

 

https://mswjs.io/docs/api/setup-worker/

 

setupWorker

Configure the interception of requests in a browser.

mswjs.io

가장 좋은 친구는 공식문서이다. 영원한 친구는 공식문서이다. 공식문서는 배반하지 않는다. 찬양 경배..! 

 

 

필요한 준비물.

  • handler.ts ->(이름은 본인이 편한 대로 지으면 됨. 나 같은 경우는 OCRReturnHandler.ts, PillSearchHandler.ts)
  • index.ts
  • browser.ts
  • server.ts
  • 더미데이터. json
  • Main.tsx 에 워커추가
  • package.json에 워커경로 추가

 

더미데이터. json (ocrReturnDummy.json)

[{
    "drugName": ["빨간약", "여명8008"],
    "intakeStart": null,
    "intakeEnd": null,
    "intakeCycle": null,
    "intakeInterval": null,
    "hospital": "중앙병원",
    "disease": null
}]

 

제이슨 형식으로 더미 데이터를 만들어준다. API명세서에 있는 명세 기반으로 만들어주고.

 

handler.ts(OCRReturnHandler.ts)

import { http, HttpResponse } from 'msw';
import ocrReturnDummy from '../dummy/register/ocrReturnDummy.json';

export const ocrReturnhandler = [
  http.get('테스트를 원하는 URL주소를 입력하세용.', async () => {
    const ocrReturnDummyData = await ocrReturnDummy;
    console.log('msw 서버... 응답 ... data : ', ocrReturnDummy);
    return HttpResponse.json({ data: ocrReturnDummyData });
  }),
];

 

핸들러를 만들어준다. 핸들러의 역할은 서버로 request를 요청하면 response가 되돌아올 것이다. 즉 서버단에서 response에 값을 넣어주기 위해 어떠한 로직이 실행이 될 것이다. 그 부분이라고 생각하면 된다.

 

필자가 만든 코드의 경우에는 msw로 요청이 들어온다면, 위에서 만든 더미데이터를 받아서 response 하는 코드이다.

 

이름은 용도에 맞게 지어도 되고, 지금 드는 생각은 하나의 핸들러에 export로 다 넣어도 되겠다는 생각도 든다.

 

핸들러는 배열 형태임을 주의하자

 

browsers.ts

import { setupWorker } from 'msw/browser';
import { pillSearchHandler } from './handler/PillSearchHandler';
import { ocrReturnhandler } from './handler/OcrReturnHandler';

export const worker = setupWorker(...pillSearchHandler, ...ocrReturnhandler);

worker.start();

 

위에서 핸들러를 열심히 만들었다면. 만들었으니 부려먹어야 할 것 아닌가. worker로 등록을 해주어야 한다. 그 부분을 하는 코드이다.

 

index.ts

import { server } from './server';

server.listen();

 

서버야 잘 듣고 있니?

 

server.ts

import { setupServer } from 'msw/node';
import { pillSearchHandler } from './handler/PillSearchHandler';
import { ocrReturnhandler } from './handler/OcrReturnHandler';
export const server = setupServer(...pillSearchHandler, ...ocrReturnhandler);

 

서버에 핸들러를 등록하는 부분이다.

 

 

package.json

"msw": {
    "workerDirectory": [
      "./public",
      "public"
    ]
  }

이 부분은 무엇이냐면 위 폴더구조를 보면 public이라는 폴더가 보일 것이다. msw를 설치하면 생기는 폴더인데. msw의 설정이나 정의가 해당 폴더에 있다고 알려주는 역할이다.

 

Main.tsx(가장 최상단 컴포넌트)

//일단 다 생략했음. 기존에 있던거 지우기 X
import { server } from './mocks/server';


async function enableMocking() { //async를 한 이유는 서버가 완전히 실행이 되고 랜더링이 되도록 하기 위함임.
  if (process.env.NODE_ENV !== 'development') {
    return;
  }

  const { worker } = await import('./mock/browsers'); //웨잇어 미닛
  return worker.start();
}
enableMocking().then(() => {

  ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
    <React.StrictMode>
		여러분들의 소중한 컴포넌트들
    </React.StrictMode>,
  );

});



//원래면 아래 코드만 있는데 위 모양 처럼 감싸준거.

  ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
    <React.StrictMode>
		여러분들의 소중한 컴포넌트들
    </React.StrictMode>,
  );

 

위에서 설정을 다 했으면, 가장 최상단 컴포넌트로 가준 후. 위 주석을 따라가 보자.


안 된다면 왜 그럴까 ?

설정을 다 마치고 서버를 올리고 개발자 도구 => console에 Enable Mocking 이라고 뜨면 성공이고.

 

빨간글씨로 도배가 되어있다면 실패이다.

 

핸들러는 배열 "대괄호" 형식으로 감싸져 있어야 한다. 내가 했던 실수중 하나는 핸들러로 매개변수를 보내서 안된경우도 있었다.

import { delay, http, HttpResponse } from 'msw';
import ocrReturnDummy from '../dummy/register/ocrReturnDummy.json';

export const ocrReturnhandler = (item1, item2, item3, item4) => {
  [
    http.post('api/v1/medicines/photo/', async () => {
      const ocrReturnDummyData = await ocrReturnDummy;
      console.log('msw 서버... 응답 ... data : ', ocrReturnDummy);
      await delay(5000);
      return HttpResponse.json({ data: ocrReturnDummyData });
    }),
  ];
};

 

const 핸들러 = [내용]; 이런식으로 배열로 끝나야 하지만 위 코드는 매개변수가 들어가게 되어있는데.

useContext가 생략이 되긴 했지만.

이유는 useContext를 핸들러에서 사용하기 위해 (전역변수를 핸들러에 임포트 후 사용한다는 이야기) 인자값을 받도록 만든게 원인이였음.

 

"연동은 되지만 호출한 컴포넌트에서 값이 안보여요"


이경우는 비동기 처리가 되지않아, 핸들러에서 값을 뱉어주기전에 다음 로직으로 넘어간 경우이다.

 

위에서 정의한 핸들러를 보면 async랑 await가 있는데 그 이유가 위와 같은 이유이다.

 

사실 비동기가 너무 어려웠었다.

 

"핸들러를 배열에 넣을때 대소문자 착각"

 


마무리.

msw의 개념 및, 보편적인 사용법은 검색하면 널리고 널렸다, 내가 기록하고 싶은 것은. 내가 스스로 부딪히면서 이해하기? 힘든 부분을 내가(?) 언제 봐도 이때 이 부분이 어려웠구나를 기록하고 싶었다. 

 

위는 기초적인 연동이고, 공식문서가 너무 잘 되어있어서 이 이후에 사용함에 있어 크게 어려움은 없었다!!