본문 바로가기

프로그래밍 공부내용/리액트(React)

1. Introduction - MSW (Mocking Service Worker) 공식문서 따라 읽기 및 사용설명

한글화 문서들이 많이 없는 것 같아서.. 공부하는 겸 한글화를 동시에 진행하도록 하겠습니다.

 

공식문서 자체 내용은 기본 폰트로, 제가 추가한 내용은 노란폰트로 작성하도록 하겠습니다.

 

원본은 여기있습니당

https://mswjs.io/docs/

 

Introduction

What is Mock Service Worker?

mswjs.io

 

 

소개

 

msw는 실제 request를 가로채기위해서 service worker를 사용하는 api mocking 라이브러리입니다.

 

mock이란 '가짜의' 란 뜻입니다. api를 실제로 작동시키지 않고도 가짜값을 사용할 수 있게 하는 것을 말함.

Service Worker Api란 응용프로그램, 브라우저, 네트워크 사이의 프록시 서버 역할을 하는 api.를 말함.

탐색과 리소스 요청을 가로채 수정하고, 웹 앱이 동작하는지를 바꿀 수 있는 녀석

 

service worker를 이용해서 캐싱목적으로 요청을 잡아냄으로써, msw는 네트워크 통신체인에서 가장 높은 단에서의 모킹을 가능하게 합니다. msw는 서버를 직접 만들지 않고도 api 요청을 가장 근사하게 mocking 하는 방법입니다.

 

service worker가 표준 api로써 요즘 브라우저에 탑재돼 있기 때문에, msw를 프로젝트와 test에 추가할때 worker file을 설치하고 mock을 선언하는 것 외에는 별다른 설정이 필요하지 않을 겁니다.

 

 

언제 mock API를 써야하는지?

 

개발

소프트웨어는 애자일하고 경쟁적인 환경에서 개발이 이뤄지기 때문에,

api가 완성되기를 기다리는 것은 좋은 생각은 아닐 수 있습니다.

특정한 단계에 적용된다면, mocking은 아주 좋은 경험이 될 겁니다.

agile이 좀 핫한 키워드라서.. 뜻이 애매하지만.. 자주 바뀐다 정도로 이해하면 될 것 같습니다.

 

디버깅

대부분의 client-side-issues는 data와 연관돼 있습니다.

무효한 api요청, error handling 빠트림, 예상못한 응답 등이 있겠죠.

그런 일들은 개발단계에서 일어나든 상품이 된 후에 일어나든 흔하게 일어납니다.

 

api mocking은 개발자들이 정확한 api 상호 작용을 모델링할 수 있도록 도와줍니다.

그렇게 하면 디버깅과 문제해결에 아주 효과적일 뿐만 아니라 성공적인 시나리오를 만들 수 있습니다.

 

경험

솔직히 말해서, 우리가 개발중에 하는 선택들은 항상 최고는 아닙니다.

기술적 의심과 과거의 구조적 결정은 우리의 제품을 진화시키고 새로운 기술을 시도하는데 방해가 될 수 있습니다.

mock은 새 어플리케이션을 만들지 않아도, 다르게 만들어져도 되는지 알려줄 수 있습니다.

 

 

Service Worker여야 하는가?

msw는 network 단에서의 요청을 가로채는 service worker를 계승발전했습니다.

이런 특징은 mock을 하든 안하든 어플리케이션이 동일한 행동을 하도록 보장해줍니다.

devTools의 network를 통해서 요청을 확인해보세요.

mocking중이라는 것도 눈치채지 못할 겁니다.

 

 

어떻게 작동하는가

msw는 선언적 request handler 가 URL, RegExp, custom criteria에 근거해서 요청을 잡도록 합니다.

그 후 mock response 를 반환하는 response resolver function을 제공합니다.

regexp는 정규표현식입니다. custom criteria는 hash등의 방식으로 데이터를 url뒤에 붙이는게 아닐까 생각이 드네요.

 

아래는 POST /login 요청을 mock하는 mock정의 파일 예시입니다.

 

// src/mocks.js
import { setupWorker, rest } from 'msw'

const worker = setupWorker(
  rest.post('/login', (req, res, ctx) => {
    const isAuthenticated = sessionStorage.getItem('username')

    if (!isAuthenticated) {
      return res(
        ctx.status(403),
        ctx.json({
          errorMessage: 'Not authenticated',
        }),
      )
    }

    return res(
      ctx.json({
        firstName: 'John',
      }),
    )
  }),
)

// Register the Service Worker and enable the mocking
worker.start()

후에 이 mock definition file은 내 프로젝트에 맞춰서 import 해서 쓰게 됩니다.

 

 

Request flow diagram

 

Browser

이 라이브러리는 어플리케이션의 request를 fetch Event를 통해서 듣고 있는 service worker를 등록해줍니다.

또한 이 request 들을 client-side-library로 전달하고, mocking 된 응답을 반응할 worker에게 보냅니다.

service worker를 확장했다는 것과 이 설명을 보니까 service worker를 좀 더 쉽고, 확장성 있게 사용하도록 만든 라이브러리가 msw 라는 설명을 계속 하고 있다는 생각이 듭니다.

 

아래는 high-level-overview(추상화 한 개요를 말하는듯) msw의 request flow입니다. 

(https://github.com/mswjs/msw 여기서 코드 자체가 어떻게 돼 있는지 볼수 있다고 하네요.)

위의 플로우만 봤을 때 msw를 이용해서 등록한 service worker가 요청을 가로채면,

msw(위에서 client-side-library 인 듯) 로 보내준다음에 그걸 다시 service worker로 보내서 brower로 전달 하는 것 같습니다.

 

 

Node

service worker가 browser환경에서만 작동하기 때문에, msw는 같은 mock 정의를 노드에서도 쓰기 위해서 지정된 api를 제공합니다.(예를들면 test 목적)

 

 

전통적인 mocking 방식

대부분의 mock 라이브러리들은 아래 두가지 방식으로 작동합니다.

- 지정된 mocking server 를 가지고 있음. 이걸 이용해서 서버를 '대체' 하는 방식

- http/https/fetch 등을(native) stub 해서 request 를 가로 챔

 

stub이라는 말이 좀 애매한데요.. 테스트 코드를 작성하거나 했던 경험상 stub을 쓰면 보통 함수의 반환값을 임의로 지정해주는 임시 함수를 만들어서 갈아끼워주거나 하는 역할이었던 것 같습니다.

예를 들면 로또번호를 랜덤으로 생성한다고 하면 random을 테스트 하기 힘드니까, random 반환함수를 stub해서 내가 지정한 값을 주도록 갈아끼워주는 방식입니다.

 

1. mocking server 를 이용했을 때의 issue

실제와 mocking 된 녀석의 구조적, 기술적, infrastructure 차이 때문에

대체할 mocking server를 만드는 방식은 실제 production과 비교했을 때 차이가 많이 날 수 있습니다.

따라서 mocking과 production은 양변가능하지 않고, 어플리케이션에 이상을 만들 수 있습니다.

 

서버를 만든다는 것은 그것을 실행하고 유지해야 함을 말합니다.

실제 server의 적용을 배끼는것은 빠르고 유연한 개발 패턴이라기보다는, 노력이 많이 드는 작업입니다.

게다가 mocking server는 실제 server와는 다른 server입니다.

mock server만의 특정한 실행 시나리오를 가지고 있고, 앱 자체의 코드 수정이 불가피 할 수도 있습니다. 

그리고 이것은 유지보수 비용이 많이 드는 작업입니다.

 

간단하게 말해서 mocking만을 위한 server가 하나 더 생기는 거라 코드에 가해야할 작업량이 많아지고, 실제 server와 완전 똑같지도 않아서 별로라는 뜻입니다.

 

2. stub 했을 때의 issue

native 요청을 argument 하는 것은 어플의 동작을 유지하면서 요청을 가로채는 효과적인 방법입니다.

하지만 native code에 변화를 주는 것은 mocking과 non-mocking 환경 사이에 문제를 만들 수 있습니다.

실제로 내가 갖지도 않은 요청을 흉내내는 것은 추천할만한 방식은 아닙니다.

 

이런 접근은 괜찮은 절충안이지만, 기술적 한계를 가집니다.

native를 stub해야하는 한계때문에 앱의 행동에 부분적인 확신밖에 못가집니다.

이것은 e2e 테스트를 위한 최적의 방법은 아닙니다.

 

stub을 하게 되는 것도 실제 서비스와의 괴리는 있다. random 대신 1만 주는 로또번호 생성기로 만들어서 나머지가 잘 작동하는지 확인하는 방식으로는 사용자면에서 제대로 테스트를 한다거나 할 수 없다는 뜻 인거 같습니다.

 

 

 

 

전체적으로 문제들을 좍 나열하고, 어떤게 장점인지 써놨는데...

아직 안써봐서 실제 이 말처럼 잘 작동하는지 모르겠네요.

사실 stub이랑 비슷한 거라고 알고 있었는데, stub의 issue들을 나열해 놔서 어떤식으로 극복했을지 기대가 됩니다.

Getting start 는 간단히 실행을 해보고 나서 다시 읽고 이어서 작성하겠습니다.