에뮬레이션 서비스 시작

나는 최근에 켄트 C. 도드의 글을 보았는데, 그가 모의 서비스 종사자 도서관을 언급했다.지금 나는 이미 그것과 한동안 합작했기 때문에, 나는 그것을 사랑하게 되었다.
보아하니 많은 사람들도 그렇다.MSW는 올해 자바스크립트 오픈소스 어워드에서'가장 감동적인 기술 사용'award을 받았다.
MSW의 기능과 프런트엔드 테스트에서 MSW를 사용하는 방법 및 이유를 살펴보겠습니다.
테스트를 실행할 때 실제 API에 연결하지 않기를 원합니다. 왜냐하면...
  • 테스트 및
  • 실행 시 운영 데이터에 영향을 주지 않으려는 경우
  • 실행 중인 테스트에 따라 API가 반환되는 내용을 제어하고자 합니다.
  • 그러나 프로그램이 정상적으로 실행되기 위해서는 API와 상호작용을 해야 한다. 이것은 실제 API를 모의하는 가짜 API가 필요하다는 것을 의미한다.이것이 바로 도시 고체 폐기물의 원천이다.
    MSW 정의 프로세서를 사용하면 프런트엔드에서 요청을 차단하고 프로세스 논리로 응답하는 진정한 API 역할을 합니다.

    그런데 제가 되찾는 척 하면 안 돼요?


    일반적인 경우, 테스트 전단에 있으면,fetch를 모방하거나,axios를 모방하지만, MSW는 실제 서버를 충당하기 때문에, 응용 프로그램이 실제 API에 연결된 것처럼 연결됩니다.
    이것은 응용 프로그램이 아날로그 API를 연결하고 있는지도 모른다는 것을 의미한다.당신의 응용에 있어서, 이것은 단지 사무실의 또 다른 날일 뿐입니다.이것은 테스트와 생산 중의 동일한 행위를 보장한다.그래서...
  • 가능한 한 현실적으로 프런트엔드를 테스트하고 있습니다
  • .
  • 코드가 어떻게 사용되는지 테스트하는 것이지 어떻게 사용되는지 테스트하는 것이 아닙니다.데이터 획득 라이브러리를 변경하면 모든 것이 정상입니다.
  • 우리 시작합시다!


    SWR 라이브러리를 사용하여 대기사항 목록을 가져오는 대기사항 목록 프로그램이 있습니다.todo를 삽입할 때fetch를 사용하여POST 요청을 보냅니다.
    여기서 보기live example.여기에 삽입된 작업은 개인 작업이며 다른 사용자와 공유되지 않습니다.
    클론 재구매 계약을 시작한 후 다음을 수행합니다.
    git clone [email protected]:jacques-blom/taskhero-web.git
    cd taskhero-web
    yarn
    

    1단계: 에뮬레이션 서비스 인력 설정


  • 먼저 MSW 패키지를 설치합니다.
    npm install msw --save-dev
    # or
    yarn add msw --dev
    

  • 다음은 아날로그 API 프로세서를 저장하기 위한 폴더mocks와 파일을 만듭니다.
    mkdir src/mocks && touch src/mocks/handlers.ts
    
    항목이 JavaScript로 작성된 경우 .js 파일을 사용할 수 있지만 Taskhero 항목에서는 TypeScript를 사용합니다.

  • 이제 우리는 첫 번째 시뮬레이션을 추가할 수 있다.빈 작업 그룹을 되돌려 주는 시뮬레이션 /tasks GET 단점을 보여 줍니다.
    // src/mocks/handlers.ts
    
    import {rest} from 'msw'
    import {getApiUrl} from '../components/api'
    
    export const handlers = [
        // Handles a GET /tasks request
        rest.get(getApiUrl('/tasks'), (req, res, ctx) => {
            // Returns an empty array JSON response
            return res(ctx.json([]))
        }),
    ]
    
    💡 여기에 우리가 사용하는 것은 getApiUrlutil입니다.이렇게 하면 시뮬레이션하려는 전체 URL이 반환됩니다.MSW는 정확한 URL 일치가 필요하기 때문에 매우 중요합니다.따라서 API가 http://localhost:8080/tasks로부터 데이터를 가져오면 rest.get('http://localhost:8080/tasks')뿐만 아니라 rest.get('/tasks')도 정확하게 지정해야 합니다.

  • 그런 다음 Jest를 실행하려면 /src/mocks/server.ts라는 파일을 만듭니다.
    touch src/mocks/server.ts
    

  • 여기서, 우리는 서버를 시작하여 처리 프로그램에 전송할 것이다.
    // src/mocks/server.ts
    
    import {setupServer} from 'msw/node'
    import {handlers} from './handlers'
    
    export const server = setupServer(...handlers)
    

  • 현재 우리는 테스트를 실행할 때 서버를 시작해야 한다.농담으로 이 점을 하기 위해서 다음 코드를 설치 파일에 추가합니다.
    Taskhero 응용 프로그램에서 Create React 응용 프로그램을 사용하기 때문에 기존 src/setupTests.ts 파일에 간단하게 추가할 수 있습니다.
    CRA 없이 어떻게 설정하는지 알아보기MSW docs.
    // src/setupTests.ts
    
    import {server} from './mocks/server'
    
    // Start the server before all tests.
    beforeAll(() => server.listen())
    
    // Reset any handlers that we may add during individual tests,
    // so they don't affect other tests.
    afterEach(() => server.resetHandlers())
    
    // Stop the server after all tests have run.
    afterAll(() => server.close())
    
  • 현재 저희 서버가 테스트 실행 중입니다. 테스트 중의 요청이 차단됩니다!
  • 2단계: 첫 번째 테스트 작성

  • App.test.tsx 구성 요소의 테스트를 포함하는 App 파일을 만듭니다.
    touch src/App.test.tsx
    

  • 이제 우리는 첫 번째 테스트를 작성할 수 있다.프로그램이 /todos 단점에서 데이터를 불러올 때 불러오는 화면을 표시하는지 테스트할 것입니다.
    import React from 'react'
    import {render, screen} from '@testing-library/react'
    import App from './App'
    import {GlobalWrapper} from './testUtils'
    
    it('shows the loading spinner while data is loading', () => {
        render(<App />, {wrapper: GlobalWrapper})
        expect(screen.getByRole('alert', {name: 'loading'})).toBeInTheDocument()
    })
    
    무슨 일이 일어났는지 분석해 봅시다.
    우선, 우리는 App 구성 요소를 보여 줍니다. GlobalWrapper로 포장하고, 이 구성 요소는 응용 프로그램에 필요한 모든 상하문 공급자를 설정합니다.
    그 다음에, 우리는 모뎀을 가져와서 문서에 나타나기를 기대합니다.
  • 지금 첫 번째 테스트가 있습니다!
  • 모범 사례 참고 사항: 역할별 조회 및 스크린 사용


    너는 여기에 두 가지 테스트 기술이 있다는 것을 알게 될 것이다. 나는 그것들이 매우 좋은 실천이라고 생각한다.
  • screen를 사용하여 모든 조회를 진행합니다.screen.getByLabelText로 대체const {getByLabelText} = render(...).끊임없이 render 해체 구조에 방법을 추가할 필요가 없기 때문에 생활이 더욱 간단해질 뿐이다.

  • 조회 방식은 화면 판독기와 같다.
    그게 더 중요해.테스트 id로 조회하는 것이 아니라 원소의 접근 가능한 이름으로 원소를 조회합니다.이것은 테스트가 변화에 더욱 적응할 수 있을 뿐만 아니라, 단추를 구축하는 방식을 완전히 바꾸더라도, 더 쉽게 접근할 수 있는 코드를 작성하도록 권장합니다.
  • 이 두 가지 견해는 켄트 C. 도드(Kent C.Dodds)의 우수한 문장Common mistakes with React Testing Library에서 나온 것으로 이 문장을 읽는 것을 강력히 추천합니다.

    3단계: 로드 상태 처리


    사용자가 작업이 없으면 프로그램이 '작업이 없습니다' 메시지를 보일 지 테스트해 봅시다.
    it('shows an alert if there are no tasks', () => {
        render(<App />, {wrapper: GlobalWrapper})
        expect(screen.getByRole('heading', {name: /No tasks yet/i})).toBeInTheDocument()
    })
    
    너는 우리의 테스트가 실패했다는 것을 알아차릴 것이다.이것은 우리가 expect 테스트를 진행할 때 데이터가 여전히 불러오고 있기 때문이다.로드 상태가 사라질 때까지 코드를 추가합니다.
    -import {render, screen} from '@testing-library/react'
    +import {render, screen, waitForElementToBeRemoved} from '@testing-library/react'
    
    -it('shows an alert if there are no tasks', () => {
    +it('shows an alert if there are no tasks', async () => {
         render(<App />, {wrapper: GlobalWrapper})
    +    await waitForElementToBeRemoved(() => screen.getByRole('alert', {name: 'loading'}))
         expect(screen.getByRole('heading', {name: /No tasks yet/i})).toBeInTheDocument()
     })
    
    여기에서 DOM 테스트 라이브러리의 waitForElementToBeRemoved 함수를 사용하여 불러오기를 기다립니다.

    4단계: 특정 프로세서 테스트


    다음에 API가 오류를 반환하면 응용 프로그램에서 오류 메시지가 표시되는지 테스트할 수 있습니다.이를 위해 테스트에 직접 포함된 다른 프로세서 덮어쓰기/tasks의 기본 프로세서를 사용할 수 있습니다.server.resetHandlers()를 추가하여 모든 테스트 후에 실행할 것을 기억하십시오. 이것은 다음 처리 프로그램이 이 테스트에만 존재한다는 것을 의미합니다.)
    // src/App.test.tsx
    
    import {server} from './mocks/server'
    import {rest} from 'msw'
    import {getApiUrl} from './components/api'
    
    it('shows an error message if the API returns an error', async () => {
        // Inline handler just for this test
        server.use(
            rest.get(getApiUrl('/tasks'), (req, res, ctx) => {
                // Use ctx.status to return a specific status code
                return res(ctx.status(500), ctx.json({message: 'Internal server error'}))
            }),
        )
    
        render(<App />, {wrapper: GlobalWrapper})
        await waitForElementToBeRemoved(() => screen.getByRole('alert', {name: 'loading'}))
        expect(screen.getByRole('heading', {name: /error/i})).toBeInTheDocument()
        expect(screen.getByRole('alert', {name: /internal server error/i})).toBeInTheDocument()
    })
    
    하지만 우리의 테스트는 실패했다!테스트에서 불러오는 상태를 찾을 수 없습니다.반면 응용 프로그램은 "아직 작업이 없습니다!"만 나타낸다.당장 메모 남겨.FE 테스트의 난제를 불러왔습니다.

    주의 캐시


    위에서 우리가 겪고 있는 문제는 라이브러리 SWR 캐시 응답을 얻기 위해 사용하는 데이터입니다.따라서 캐시 응답이 있으면 즉시 되돌아옵니다.SWR, React Query, Apollo Client 등 많은 데이터 취득 라이브러리에는 문제를 일으킬 수 있는 캐시 동작이 있다.
    이 문제를 해결하기 위해서는 테스트 사이에 SWR 캐시를 제거해야 합니다.이렇게 하려면 테스트 설정 파일afterEach에 다음을 추가합니다.
    +import {cache} from 'swr'
    
     afterEach(() => {
    +    cache.clear()
         server.resetHandlers()
     })
    
    또한 dedupingInterval: 0 구성 요소의 SWRConfigGlobalWrapper 추가해야 합니다. 이 구성 요소는 모든 테스트를 포함합니다.
    // src/testUtils.tsx
    
    -<SWRConfig value={{fetcher: fetcher, shouldRetryOnError: false}}>
    +<SWRConfig value={{dedupingInterval: 0, fetcher: fetcher, shouldRetryOnError: false}}>
    
    그렇지 않으면 SWR은 일정 시간을 기다려서 보여주는 사이에 같은 요청이 있는지 확인합니다. 이것은 하나의 조정으로 실행할 수 있습니다. 이것은 우리가 같은 단점을 호출하지만 다른 응답을 기대하는 두 개의 테스트가 있다면 SWR는 이 두 요청을 하나로 통합할 것입니다.
    나는 모든 유행하는 데이터 획득 라이브러리의 캐시 문제를 어떻게 해결하는지에 대한 단독 글을 쓸 수도 있다.어떤 데이터 획득 라이브러리를 사용하십니까!

    우리 모든 시험 다 통과했어!다음은요?


    (당신은 완전한 코드와 우리가 추가한 모든 내용을 볼 수 있습니다here. 그리고 여기서 볼 수 있습니다diff comparison
    이제 프런트엔드를 테스트하기 위해 MSW를 설정하는 방법과 테스트를 작성하는 방법을 알 수 있습니다.아직 해야 할 일이 많다.다음 게시물에서는 다음을 확인할 수 있습니다.
  • POST 요청 테스트
  • 루트 파라미터가 있는 테스트 요청입니다.
  • 테스트 퀘스트 목록, 빈 상태만 있는 것이 아니다
  • 뭐가 유용하고 뭐가 아니야.
  • 당신의 테스트를 어디에 두세요.
  • 및 그 이상입니다.
  • 향후 게시물에서는 사이프레스 설정 MSW를 사용하여 종합적인 테스트를 하는 방법도 소개할 것이다.
    다음 댓글을 올릴 때 알림을 받고 싶으면
    문제가 있으면 언제든지 연락 주세요.
    만약 이 글이 도움이 된다고 생각하고 다른 사람들도 그럴 것이라고 생각한다면 사랑을 전파하고 공유하는 것을 고려해 보세요.

    좋은 웹페이지 즐겨찾기