MSW๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—๋Ÿฌ ์‘๋‹ต์„ ๋ชฉ์—…ํ•˜๊ณ  ๋Ÿฐํƒ€์ž„์—์„œ ์‰ฝ๊ฒŒ ๊ฐˆ์•„๋ผ์šฐ๊ธฐ

๊ณฐํ„ฐ๋ทฐ์—์„œ MSW๋กœ ์ปค์Šคํ…€ ์—๋Ÿฌ ์ฝ”๋“œ๋ฅผ ์ •์˜ํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

Profile Picture
milk717
2023-12-08

์ด ๊ฒŒ์‹œ๊ธ€์˜ ์›๋ณธ ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.

๊ณฐํ„ฐ๋ทฐ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์„œ๋ฒ„์˜ ๊ฐœ๋ฐœ์†๋„์— ์ œ์•ฝ์„ ๋ฐ›์ง€ ์•Š๊ณ  ํŽ˜์ด์ง€ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด MSW๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ์š”. MSW(Mock Service Worker)๋ž€ ์„œ๋น„์Šค ์›Œ์ปค API๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์ œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๊ณ , ๋ฏธ๋ฆฌ ์ •์˜๋œ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ด ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์—†์ด๋„ HTTP ์š”์ฒญ์„ ๋ชจ๋ฐฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ๊ณฐํ„ฐ๋ทฐ ํ”„๋ก ํŠธ์—”๋“œ๋Š” MSW ๋•๋ถ„์— ๋ฐฑ์—”๋“œ API ๋ฐฐํฌ ์†๋„์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ณ  ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ๋น ๋ฅด๊ฒŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์šฐ๋ฆฌํŒ€์ด MSW๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•ด์„œ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”์ง€์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

MSW ๋น ๋ฅด๊ฒŒ ๋ชฉ์—…ํ•˜๊ธฐ

MSW๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฃผ๋œ ์ด์œ  ์ค‘ ํ•˜๋‚˜๋Š” ๋ฐฑ์—”๋“œ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ณ  ํ”„๋ก ํŠธ์—”๋“œ์˜ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ MSW๋ฅผ ๋ชฉ์—…ํ•˜๋Š”๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค๋ฉด ๋น ๋ฅธ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด ๋„์ž…ํ–ˆ๋˜ MSW๊ฐ€ ์–ด๋Š์ƒˆ ๊ณจ์น˜์•„ํ”ˆ ํƒœ์Šคํฌ๊ฐ€ ๋ผ๋ฒ„๋ฆฌ์ฃ . ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ ํŒ€์€ ์ตœ์†Œํ•œ์˜ ๋น„์šฉ์œผ๋กœ ์‘๋‹ต์„ ๋ชฉ์—…ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

response body๋ฅผ ์œ„ํ•œ json ๋”๋ฏธ๋ฐ์ดํ„ฐ ์ƒ์„ฑ

์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋ƒˆ์„ ๋•Œ response ์‘๋‹ต์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๊ณณ์—์„œ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋“  response ์‘๋‹ต์„ json ํŒŒ์ผ ํ˜•์‹์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ json ํŒŒ์ผ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์„ ๊ธฐ์ค€์œผ๋กœ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๋ณ„๋กœ ๋‚˜๋ˆ ์ง„ response body ๋ฐ์ดํ„ฐ MSW ํ•ธ๋“ค๋Ÿฌ์—์„œ ๋ฐ”๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ์‘๋‹ต์„ ๋‚ด๋ ค์ฃผ์ง€ ์•Š๊ณ  ๋ณ„๋„์˜ json์œผ๋กœ ๊ด€๋ฆฌํ•œ ์ด์œ ๋Š” ์ถ”ํ›„ ์—๋Ÿฌ ์ƒํ™ฉ์— ๋Œ€ํ•œ ํ•ธ๋“ค๋Ÿฌ๋“ค์ด ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ๋„ ์ผ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ ์•„๋ž˜ ์—๋Ÿฌ์‘๋‹ต์— ๋ชฉ์—…์— ๋Œ€ํ•ด ์„ค๋ช…ํ•  ๋•Œ ๋” ์ž์„ธํžˆ ์–ธ๊ธ‰ํ•˜๋„๋ก ํ• ๊ฒŒ์š”.

ํด๋ผ์ด์–ธํŠธ์˜ ์‘๋‹ต์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ  ์„ฑ๊ณต ์‘๋‹ต์„ ๋‚ด๋ ค์คŒ

http.post(API.ANSWER, () => {
  return HttpResponse.json({}, { status: 201 });
}),
http.post(API.ANSWER_DEFAULT, ({ request }) => {
  return HttpResponse.json({}, { status: 201 });
}),

POST, PATCH๋“ฑ ํด๋ผ์ด์–ธํŠธ์˜ request body์— ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ์‘๋‹ต์„ ๋‚ด๋ ค์ค˜์•ผ ํ•˜๋Š” ์š”์ฒญ์˜ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋‚ธ ์‘๋‹ต์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ  ๋ฌด์กฐ๊ฑด ์„ฑ๊ณต ์‘๋‹ต์„ ๋‚ด๋ ค์คฌ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์‘๋‹ต ๊ฒ€์ฆ ๋กœ์ง์ด ์ถ”๊ฐ€๋˜๋Š” ์ˆœ๊ฐ„ MSW๋ฅผ ๋ชฉ์—…ํ•˜๋Š”๋ฐ ๊ต‰์žฅํžˆ ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๊ธฐ ๋•Œ๋ฌธ์ธ๋ฐ์š”. MSW๊ฐ€ ์ฑ…์ž„์ ธ์•ผ ํ•  ๊ฒƒ์€ ๋ฐฑ์—”๋“œ API๊ฐ€ ๋ฐฐํฌ๋˜๊ธฐ ์ „ ํด๋ผ์ด์–ธํŠธ์—์„œ API ์—ฐ๊ฒฐ ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์šฉ์ดํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด์ง€ ์‹ค์ œ ๋™์ž‘์„ ์ œ๊ณตํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ request body๋ฅผ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ  ๋ฌด์กฐ๊ฑด ์„ฑ๊ณต ์‘๋‹ต์„ ๋‚ด๋ ค์ฃผ๋„๋ก ๋ชฉ์—…์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

json ๋ฐ์ดํ„ฐ๋กœ response body ์ƒ์„ฑ

http.get(API.ANSWER_ID(), ({ params }) => {
  const { id: answerId } = params;
  const answerIdMap = new Map<number, AnswerEntity[]>();
  answerData.forEach((answer) => {
    answerIdMap.has(answer.answerId)
      ? answerIdMap.get(answer.answerId)!.push(answer)
      : answerIdMap.set(answer.answerId, [answer]);
  });
  return HttpResponse.json(answerIdMap.get(Number(answerId)));
}),

GET ์š”์ฒญ์ฒ˜๋Ÿผ response body๊ฐ€ ํ•„์š”ํ•œ ์‘๋‹ต์˜ ๊ฒฝ์šฐ ์œ„์—์„œ ์ €์žฅํ•ด๋†จ๋˜ json ๋”๋ฏธ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€ ์‘๋‹ต์„ ์ƒ์„ฑํ•˜๋Š” ๋กœ์ง์„ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. GET์š”์ฒญ๊ฐ™์€ ๊ฒฝ์šฐ ์„œ๋ฒ„์—์„œ ๋‚ด๋ ค์ฃผ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋Š์ •๋„ ์žˆ์–ด์•ผ API ์‘๋‹ต์— ๋”ฐ๋ฅธ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ธ๋ฐ์š”. ์ด ๋˜ํ•œ ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜์ง€ ์•Š๋„๋ก json ๋ฐ์ดํ„ฐ๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐ€๊ณตํ•ด์„œ ์‘๋‹ต์„ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

์—๋Ÿฌ ์‘๋‹ต ๋ชฉ์—…ํ•˜๊ธฐ

์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋‹ˆ API ์„ฑ๊ณต ์ผ€์ด์Šค์— ๋Œ€ํ•ด์„œ ์ตœ์†Œํ•œ์˜ ์‹œ๊ฐ„๋งŒ์„ ๋“ค์—ฌ API ๋ชฉ์—…์„ ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋‹ค์–‘ํ•œ ์ผ€์ด์Šค์— ๋Œ€ํ•œ API๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„ฑ๊ณต ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—๋Ÿฌ ์ผ€์ด์Šค์— ๋Œ€ํ•œ ๋ชฉ์—…๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์—๋Ÿฌ ์‘๋‹ต์— ๋Œ€ํ•œ ๋ชฉ์—…์€ MSW ํ•ธ๋“ค๋Ÿฌ ์‘๋‹ต์˜ http status ์ฝ”๋“œ๋งŒ ์—๋Ÿฌ์ฝ”๋“œ๋กœ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„์ฃผ ๊ฐ„๋‹จํ•œ ์ž‘์—…์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋Š” ์–ธ์ œ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์กฐ๊ฑด์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ์š”. ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์—๋Ÿฌ ์ผ€์ด์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์„์ง€์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•˜๋ฉฐ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•๋“ค์„ ๊ณ ๋ คํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ•1: ํด๋ผ์ด์–ธํŠธ์˜ request body์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์—๋Ÿฌ ์ผ€์ด์Šค๋ฅผ ๋‚ด๋ ค์ค€๋‹ค

ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด, ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๋ถ„์„ํ•˜๊ณ  ๊ฒ€์ฆํ•ด์„œ ์—๋Ÿฌ ์ƒํ™ฉ์„ ๋ฐœ์ƒ์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑ์—”๋“œ ์ฝ”๋“œ ์ค‘ ์ปจํŠธ๋กค๋Ÿฌ์— ํ•ด๋‹นํ•˜๋Š” ์ฝ”๋“œ๋กœ ์ด ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด MSW๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ ๋ณด๋‹ค ๋” ๋งŽ์€ ๋น„์šฉ์ด ์†Œ์š”๋œ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ•2: ํด๋ผ์ด์–ธํŠธ์˜ api ์š”์ฒญ ์ฃผ์†Œ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์—๋Ÿฌ ์ผ€์ด์Šค๋ฅผ ๋‚ด๋ ค์ค€๋‹ค

์ •์ƒ์ ์ธ ์‘๋‹ต์„ ๋‚ด๋ ค์ฃผ๋Š” api ์š”์ฒญ ์ฃผ์†Œ๊ฐ€ api/user ๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ api/user/error ๋ผ๋Š” ์ฃผ์†Œ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์—๋Ÿฌ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•ด๋ดค์Šต๋‹ˆ๋‹ค. request body๋ฅผ ๊ฒ€์ฆํ•ด์•ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•1๋ณด๋‹จ ์ ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๊ฒ ์ง€๋งŒ, ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ api ์š”์ฒญ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ˆ˜๊ณ ๋กœ์›€์ด ์žˆ์Šต๋‹ˆ๋‹ค. 'api ์—๋Ÿฌ ์ผ€์ด์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ณผ์—ฐ ์˜ณ์€ ์‹œ๋‚˜๋ฆฌ์˜ค์ผ๊นŒ?'์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•ด๋ณธ ๊ฒฐ๊ณผ ๋ญ”๊ฐ€ ์ด์ƒํ•œ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์ฃ . ๊ท€์ฐฎ์€๊ฑธ ๊ทน๋„๋กœ ์‹ซ์–ดํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ์ด๋ ‡๊ฒŒ ๋ถˆํŽธํ•˜๊ฒŒ MSW๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ ๊ฐ™์ง„ ์•Š๋‹ค๋Š” ์˜ˆ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ฑ„ํƒํ•œ ๋ฐฉ๋ฒ•

์œ„์˜ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๋ชจ๋‘ ๋˜‘๋˜‘ํ•œ ํ•ด๊ฒฐ์ฑ…์€ ์•„๋‹ˆ๋ผ๊ณ  ํŒ๋‹จํ–ˆ๊ณ , ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์„ ์ฐพ๊ธฐ ์œ„ํ•ด ํƒ์ƒ‰ํ•ด๋ณธ ๊ฒฐ๊ณผ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ธ€์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. How do you mock different responses in real life?ย #1117

์ด ๊ธ€์˜ ์ž‘์„ฑ์ž๋„ ์ €์™€ ๋™์ผํ•œ ๊ณ ๋ฏผ์„ ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ์š”. ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ MSW์˜ ํ•ธ๋“ค๋Ÿฌ ์‘๋‹ต์„ ๊ต์ฒดํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ธ€์˜ ๋‹ต๋ณ€์—์„œ ์•„์ฃผ ํš๊ธฐ์ ์ธ ํ•ด๊ฒฐ์ฑ…์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค!! ํš๊ธฐ์ ์ธ ๋‹ต๋ณ€!

export const handlers = [
  rest.get('/api/articles/latest', (request, response, context) => {
    const pageParams = new URLSearchParams(window.location.search)
    const scenario = pageParams.get('scenario')

    // Sad path
    if (scenario === 'error') {
      return response(
        context.status(500),
        context.json({ error: 'oops!' }),
      )
    }

    // Happy path
    return response(
      context.status(200),
      context.json({ data: 'some-random-fake-data' }),
    )
  }),

์ฆ‰, ์š”์•ฝํ•˜์ž๋ฉด MSW ๋˜ํ•œ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ์œ„์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ์˜ url ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง ์ฃผ์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ธ๋ฐ์š”. ์ด์— ๋”ฐ๋ผ MSW ํ•ธ๋“ค๋Ÿฌ ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ์˜ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์ƒํ™ฉ๋ณ„ API ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณฐํ„ฐ๋ทฐ์—์„œ๋Š” ์ด ๋ฐฉ๋ฒ•์„ ์–ด๋–ป๊ฒŒ ์ ์šฉํ–ˆ์„๊นŒ?

๊ณฐํ„ฐ๋ทฐ ์„œ๋น„์Šค๋Š” ๋””ํ…Œ์ผํ•œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ์œ„ํ•ด http status ์ฝ”๋“œ ๋ฟ ์•„๋‹ˆ๋ผ ์ปค์Šคํ…€ ์—๋Ÿฌ์ฝ”๋“œ๋ฅผ ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ์š”. ์ด ๋ชจ๋“  ์—๋Ÿฌ ์ƒํ™ฉ์„ ํ•˜๋‚˜์˜ ํ•ธ๋“ค๋Ÿฌ ์ฝ”๋“œ ์•ˆ์—์„œ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋”ฐ๋ผ ๋ถ„๊ธฐ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์€ ํ•ธ๋“ค๋Ÿฌ์˜ ๊ฐ€๋…์„ฑ์„ ์ €ํ•˜์‹œํ‚ค๊ณ , ๋ถˆํŽธํ•œ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ข€ ์ฐพ์•„๋ดค๋”๋‹ˆ Network behavior overrides - Mock Service Worker๋ผ๋Š” ๊ธ€์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์˜ ์„ค๋ช…์„ ์š”์•ฝํ•˜์ž๋ฉด, setupWorker๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ , worker.use ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด ๋™์ ์œผ๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฅผ ์ ์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด MSW browser์˜ ์ง„์ž…์ ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์˜ url ์ฃผ์†Œ์— ๋”ฐ๋ฅธ ํ•ธ๋“ค๋Ÿฌ ๊ต์ฒด

const isScenarioName = (str: string): str is keyof typeof scenarios => {
  return str in scenarios;
};

const scenarioName =
  new URLSearchParams(window.location.search).get('error') || 'default';
export const worker = setupWorker();

isScenarioName(scenarioName)
  ? worker.use(...scenarios[scenarioName])
  : worker.use(...scenarios.default);
  • isScenarioName ํ•จ์ˆ˜๋Š” ํƒ€์ž… ๊ฐ€๋“œ๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
  • scenarioName์—์„œ ํด๋ผ์ด์–ธํŠธ์˜ url ์ฟผ๋ฆฌ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • setupWorker๋กœ MSW๋ฅผ ์ดˆ๊ธฐํ™” ํ•œ ํ›„
  • worker.use(...scenarios[scenarioName])์œผ๋กœ ํด๋ผ์ด์–ธํŠธ url ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์— ๋”ฐ๋ฅธ MSW ํ•ธ๋“ค๋Ÿฌ ์ง‘ํ•ฉ์„ ์„ค์ •ํ•ด์ค๋‹ˆ๋‹ค.

์ƒํ™ฉ๋ณ„ ํ•ธ๋“ค๋Ÿฌ

export const scenarios = {
  default: defaultHandlers,
  a01: A01ErrorHandlers,
  a02: A02ErrorHandlers,
  c02: C02ErrorHandlers,
  m01: M01ErrorHandlers,
  q01: Q01ErrorHandlers,
  q02: Q02ErrorHandlers,
  server: serverErrorHandlers,
  t01: T01ErrorHandlers,
  t02: T02ErrorHandlers,
  v01: V01ErrorHandlers,
  v02: V02ErrorHandlers,
  v03: V03ErrorHandlers,
  v04: V04ErrorHandlers,
  v05: V05ErrorHandlers,
  v06: V06ErrorHandlers,
  v07: V07ErrorHandlers,
  v08: V08ErrorHandlers,
  w01: W01ErrorHandlers,
  w02: W02ErrorHandlers,
  w03: W03ErrorHandlers,
};

ํด๋ผ์ด์–ธํŠธ์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์œผ๋กœ ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’์€ ๊ฐ ์ปค์Šคํ…€ ์—๋Ÿฌ ์ฝ”๋“œ์— ํ•ด๋‹นํ•˜๋Š” ํ•ธ๋“ค๋Ÿฌ ์ง‘ํ•ฉ์— ๋Œ€์‘๋ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ ์ง‘ํ•ฉ ๋‚ด๋ถ€์˜ ํ•ธ๋“ค๋Ÿฌ๋“ค ๊ฐ ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ ์ง‘ํ•ฉ ๋‚ด๋ถ€์—๋Š” ์„ฑ๊ณต ํ•ธ๋“ค๋Ÿฌ ์‘๋‹ต๊ณผ ๋กœ์ง์€ ๋™์ผํ•˜์ง€๋งŒ T01 ์—๋Ÿฌ์— ํ•ด๋‹นํ•˜๋Š” ์ผ€์ด์Šค๋“ค์€ T01์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์‘๋‹ต์ด ๋‚ด๋ ค์˜ต๋‹ˆ๋‹ค.

โœจ๊ฒฐ๊ณผโœจ

error=default๋กœ ์„ค์ •๋˜์–ด ์žˆ์„ ๋•Œ๋Š” ์ •์ƒ์ ์ธ api ์‘๋‹ต์ด ๋‚ด๋ ค์˜ค๊ณ , ์ด ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์„ error=t01๋กœ ๊ต์ฒดํ•˜๋Š” ์ˆœ๊ฐ„ MSW ํ•ธ๋“ค๋Ÿฌ ์ง‘ํ•ฉ์ด T01ErrorHandlers๋กœ ๋ณ€๊ฒฝ๋˜์–ด ์—๋Ÿฌ ์ƒํ™ฉ์— ๋Œ€ํ•œ api ์‘๋‹ต์ด ๋‚ด๋ ค์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ›„๊ธฐ

'์—ญ์‹œ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ถˆํŽธํ•จ์„ ๊ฐ์ˆ˜ํ•  ๋ฆฌ๊ฐ€ ์—†์–ด!'๋ผ๋Š” ์ƒ๊ฐ์ด ์ ˆ๋กœ ๋“ค๊ฒŒ ํ•˜๋Š” ํ•ด๊ฒฐ์ฑ…์ด์—ˆ๋Š”๋ฐ์š”. ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ต์ฒดํ•œ๋‹ค๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์ถฉ๊ฒฉ์ ์ด๊ฒŒ ํš๊ธฐ์ ์ด๊ณ  ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์ด๋ผ ๊ผญ ๋ชจ๋‘์—๊ฒŒ ๋„๋ฆฌ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ถˆํŽธํ•จ์€ ์‚ด์ง ๋‚จ์•„์žˆ๋Š”๋ฐ์š”. ๋ฐ”๋กœ ์ˆ˜๋งŽ์€ ์—๋Ÿฌ ์ƒํ™ฉ์— ๋Œ€ํ•œ ํ•ธ๋“ค๋Ÿฌ ์ง‘ํ•ฉ์„ ๋ชจ๋‘ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค๋Š” ์  ์ž…๋‹ˆ๋‹ค. ๊ณฐํ„ฐ๋ทฐ์˜ ์ˆ˜๋งŽ์€ ์ปค์Šคํ…€ ์—๋Ÿฌ ์ฝ”๋“œ์— ๋Œ€ํ•œ MSW ํ•ธ๋“ค๋Ÿฌ... ์ € ๋ชจ๋“  ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋‹จ์ˆœ ๋ฐ˜๋ณต ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ฐธ ์•„๊นŒ์šด ์‹œ๊ฐ„์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „์— ๋ฉ˜ํ† ๋‹˜๊ป˜ MSW์— ๊ด€ํ•œ ์งˆ๋ฌธ์„ ํ–ˆ์„ ๋•Œ plop - npm์ด๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์ถ”์ฒœ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ ๋•Œ๋Š” MSW์˜ ์ด๋Ÿฐ ์‚ฌ์šฉ๋ฒ•์„ ๋ชฐ๋ผ์„œ ๋„๋Œ€์ฒด ์–ด๋–ป๊ฒŒ ๋„์ž…ํ•ด์•ผ ํ•˜๋Š”๊ฑฐ์ง€? ํ•˜๋Š” ์˜๋ฌธ์ด ์žˆ์—ˆ๋Š”๋ฐ์š”. ์ด์ œ์„œ์•ผ ์ € ํŒจํ‚ค์ง€์˜ ํ•„์š”์„ฑ์„ ๋Š๋ผ๊ฒŒ ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์‹ค์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค.๐Ÿ˜‚๐Ÿ˜‚ ๋ณต๋ถ™ํ•˜๋‹ค๊ฐ€ ๋ฐœ์ƒํ•œ ์‹ค์ˆ˜ ๋‹ค์Œ๋ฒˆ MSW๋ฅผ ์ˆ˜์ • ์ž‘์—…์„ ํ•  ๋•Œ๋Š” plop๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋” ๋˜‘๋˜‘ํ•˜๊ฒŒ ๋ชฉ์—…์„ ํ•ด๋ณธ ํ›„ ์œ ์šฉํ•œ ํŒ์„ ๊ณต์œ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค~

[!info] ์ด ๊ฒŒ์‹œ๊ธ€์— ๋‚˜์˜จ ๋ฐฉ๋ฒ•๊ณผ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ MSW๋ฅผ ๋ชฉ์—…ํ•˜์‹  ๋ถ„์ด ์žˆ๋‹ค๋ฉด ๊ผญ ๊ณต์œ  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค ใ…Žใ…Ž

์ฐธ๊ณ  ๋งํฌ

How do you mock different responses in real life?ย #1117 Network behavior overrides - Mock Service Worker

๊ด€๋ จ PR

[NDD-344] MSW ์—๋Ÿฌ ๋ชจํ‚นํ•˜๊ธฐ, ๋”๋ฏธ๋ฐ์ดํ„ฐ json์œผ๋กœ ๋ณ€๊ฒฝ (2h/3h)

ยฉ 2024 Adultlee. All rights reserved.Made with โค by ์ด์„ฑ์ธ