-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #36 from imukyee/master
#35 Post. Mocking using msw
- Loading branch information
Showing
1 changed file
with
225 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
<!-- 발표영상 : https://www.youtube.com/watch?v=lDLFzTHrCfo --> | ||
|
||
## Mocking | ||
|
||
외부 서비스에 의존하지 않고 독립적으로 실행이 가능한 단위 테스트를 작성하기 위해서 사용되는 테스팅 기법 | ||
|
||
|
||
|
||
프론트엔드에서 백엔드의 API를 활용해야 하는 것처럼, 백엔드 개발에 종속적이 부분이 있다면 해당 부분이 완성되기 전까지는 프론트엔드의 개발을 진행할 수 없다. **->** **Mocking을 이용!** | ||
|
||
|
||
|
||
기존에는 화면에 필요한 데이터의 상태를 애플리케이션의 내부 로직에 직접 Mocking 해서 필요한 화면에 붙이거나 Mock 서버를 별도로 만들었다. | ||
|
||
그러나, 내부 로직에 직접 붙이는 경우에는, 구현이 쉽지만, 서비스 로직을 수정해야하고, HTTP 메소드와 네트워크의 응답 상태에 따라 각각 대응하기가 쉽지 않음. | ||
|
||
Mock서버를 별도로 만드는 경우에는 서비스 로직을 수정하지 않아도 되지만, 데이터 상태 구현에 비용이나 인력이 더 많이 들게 된다. | ||
|
||
또한 API 응답 상태에 따라 대기, 로딩, 에러 등의 여러가지 구현이 존재하는데, 이런 경우 각 케이스별로 임의의 상태를 만들어 보면서 개발하기 쉽지 않다! | ||
|
||
|
||
|
||
## MSW.js (Mock Service Worker) | ||
|
||
> [msw공식문서](https://mswjs.io/docs/) | ||
실제 API를 사용하는 것처럼 네트워크 수준에서 Mocking 가능하도록 해주는 라이브러리 | ||
|
||
Service Worker를 통해 HTTP요청을 가로챌 수 있기 때문에, 네트워크 요청을 보냈을 때 모의 응답을 보내줄 수 있다! 따라서 Mock서버를 구축하지 않아도 API를 네트워크 수준에서 Mocking할 수 있다. | ||
|
||
|
||
|
||
![img](https://tech.kakao.com/wp-content/uploads/2022/01/08-3.png) | ||
|
||
|
||
|
||
### 설치 및 설정 | ||
|
||
> Create-React-App 기반으로 REST API 모킹해보기 | ||
**msw 설치** | ||
|
||
``` | ||
npm install msw --save-dev | ||
# or | ||
yarn add msw --dev | ||
``` | ||
|
||
**mocks 폴더 생성** | ||
|
||
``` | ||
mkdir src/mocks | ||
``` | ||
|
||
**handlers.js** 파일 생성 | ||
|
||
``` | ||
touch src/mocks/handlers.js | ||
``` | ||
|
||
인터셉트한 request에 따라 돌려 줄 mocked응답을 작성해두는 파일이다. | ||
|
||
ex) | ||
|
||
```javascript | ||
// src/mocks/handlers.js | ||
import { rest } from 'msw' | ||
|
||
export const handlers = [ | ||
// Handles a POST /login request | ||
rest.post('/login', null), | ||
|
||
// Handles a GET /user request | ||
rest.get('/user', null), | ||
] | ||
``` | ||
|
||
**msw 초기화** | ||
|
||
``` | ||
npx msw init <PUBLIC_DIR> --save | ||
``` | ||
|
||
<PUBLIC_DIR> 은 프로젝트 starter를 무엇으로 했는지에 따라 확인하고 지정해주면 된다. | ||
|
||
CRA인 경우엔 `public/` | ||
|
||
<br> | ||
|
||
**browser.js 파일 생성** | ||
|
||
``` | ||
touch src/mocks/browser.js | ||
``` | ||
|
||
msw에서 제공하는 서비스워커를 가져와서 위에서 작성한 handlers를 인자로 넘겨준다. | ||
|
||
```javascript | ||
// src/mocks/browser.js | ||
import { setupWorker } from 'msw' | ||
import { handlers } from './handlers' // export default로 해줬을 경우 {} 제거 | ||
|
||
// This configures a Service Worker with the given request handlers. | ||
export const worker = setupWorker(...handlers) | ||
``` | ||
|
||
**서비스 워커 실행** | ||
|
||
```javascript | ||
// src/index.js | ||
import React from 'react' | ||
import ReactDOM from 'react-dom' | ||
import App from './App' | ||
|
||
if (process.env.NODE_ENV === 'development') { | ||
const { worker } = require('./mocks/browser') | ||
worker.start() | ||
} | ||
|
||
ReactDOM.render(<App />, document.getElementById('root')) | ||
``` | ||
|
||
개발 환경일 때, browser.js에서 worker를 가져와서 실행하는 코드를 추가한다. | ||
|
||
API에 대해서 모의 응답이 아닌 실제 응답을 원할 때는 이 코드만 지우고 실행하면 된다. | ||
|
||
<br> | ||
|
||
**작동 확인** | ||
|
||
컴포넌트에서 **fetch(‘/login’)** 진행 후 react 서버를 열고 콘솔을 확인했을 때 | ||
|
||
**Mocking enabled** 이라고 빨간 글씨가 적혀있다면 정상 작동하고 있는 것. | ||
|
||
|
||
|
||
### **실습** | ||
|
||
| Parameter name | Description | | ||
| :----------------------------------------------- | :--------------------------------------------------------- | | ||
| [`request`](https://mswjs.io/docs/api/request) | Information about the captured request. | | ||
| [`response`](https://mswjs.io/docs/api/response) | Function to create the mocked response. | | ||
| [`context`](https://mswjs.io/docs/api/context) | Context utilities specific to the current request handler. | | ||
|
||
```javascript | ||
// src/mocks/handlers.js | ||
import { rest } from 'msw' | ||
|
||
const handlers = [ | ||
rest.get('/users', (req, res, ctx) => { | ||
return res( | ||
ctx.status(200), | ||
ctx.delay(1000), | ||
ctx.json([ | ||
{ | ||
id: 1, | ||
name: 'deer', | ||
age: 20 | ||
}, | ||
{ | ||
id: 2, | ||
name: "coco", | ||
age: 20 | ||
}, | ||
{ | ||
id: 3, | ||
name: "ddiyong", | ||
age: 20 | ||
} | ||
] | ||
) | ||
) | ||
}), | ||
] | ||
|
||
export default handlers | ||
``` | ||
|
||
```javascript | ||
// src/MockingTest.js | ||
import { useState } from 'react' | ||
|
||
function MockingTest () { | ||
|
||
const [userData, setUserData] = useState(); | ||
|
||
function getUsersHandler() { | ||
fetch('/users') | ||
.then((res) => { | ||
return res.json() | ||
}) | ||
.then((json) => { | ||
setUserData(json) | ||
}) | ||
} | ||
|
||
return ( | ||
<div> | ||
<button onClick={getUsersHandler}>멤버</button> | ||
{userData && | ||
userData.map((user) => ( | ||
<div key={user.id}>이름 : {user.name} 나이 : {user.age}</div> | ||
)) | ||
} | ||
</div> | ||
); | ||
} | ||
|
||
export default MockingTest; | ||
|
||
``` | ||
|
||
**결과 화면** | ||
|
||
![이미지](https://pbs.twimg.com/media/FXqMWleaUAAx7iu?format=png&name=small) | ||
|
||
<br> | ||
|
||
**참고 링크들** | ||
|
||
- https://tech.kakao.com/2021/09/29/mocking-fe/ | ||
|
||
- https://han-py.tistory.com/400 | ||
|
||
- https://velog.io/@9rganizedchaos/%E3%81%93%E3%82%8C%E3%81%8C%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%88%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%EF%BC%81-%E3%80%8CMock-Service-Worker%E3%80%8D |