• 2021. 11. 7.

    by. 문익점

    반응형

    이번 포스팅에서는 Jest로 리액트 컴포넌트를 테스트하기 위해 Jest를 구성하는 방법, React Testing Library API 사용 방법을 소개합니다. Jest와 React Testing Library에 대한 설명은 앞선 포스팅을 참고해주세요. 우선 리액트에서 테스트를 진행하기 전에 Jest에서 어떻게 테스트 케이스를 작성하는 지 구조부터 보겠습니다.

    Jest의 구조

    테스트 케이스를 만들기 전 연관된 테스트 케이스들을 하나로 묶는 방법이 있습니다. 바로 describe 함수를 사용합니다. 이 describe안에는 하나 하나 개별 테스트를 수행 할 수 있는데요. 그 작업은 test함수로 실행합니다. 아래 코드를 보실까요?

    describe("Calculate Number", () => {
      test("one plus one is two", () => expect(1 + 1).toBe(2));
      test("one multiply one is one", () => expect(1 * 1).toBe(1));
    });

    describe의 함수의 첫 번째 파라메터로 그룹명이 전달괴고 두 번째는 콜백함수가 전달됩니다. Calculate Number라고 이름을 지어주었습니다. 이제 콜백 함수 안 에서 테스트 케이스들을 진행하면 되는데요. test 함수의 첫번째 파라메터로 테스트의 이름이 전달되고 두 번째는 콜백함수가 전달됩니다. 테스트의 이름은 one plus one is two라고 지어주었고 두 번째 테시트는 one multiply one is one이라고 지어주었습니다.

    보시다싶이 한 그룹안에서 여러개의 테스트가 진행이 가능합니다. 그리고 테스트들이 어떠한 연관이 있는지 그룹명을 지어주시면 됩니다.

    expect와 toBe

    expect 함수는 테스트를 작성할 때 값이 특정 조건을 충족하는지 확인해야 하는 경우에 사용됩니다. 이 함수는 matcher라는 함수와 같이 사용되는데요. 앞서 본 예제 코드의 tobe와 같은 함수들을 matcher 함수라고 부릅니다.

    () => expect(1 + 1).toBe(2)) // SUCCESS
    () => expect(1 * 1).not.toBe(1) // FAIL

    tobe는 === 와 같다고 보면 됩니다. 1 + 1 이라는 값이 2가 충족하는지 테스트하는 코드가됩니다. 결국 이 케이스를 테스트하게 되면 성공하게 되고 아래 케이스는 실패하게 됩니다.

    CRA에서 테스트 시작하기

    CRA에는 Jest와 React Testing Library가 기본적으로 포함되어 있습니다. 그래서 프로젝트를 만들고 나면 App.test.tsx와 같은 파일을 src 폴더안에서 찾아 볼 수 있는데요. 이는 CRA에서 jest 아래와 같은 파일 찾아 실행시키기 때문입니다.

    • __tests__ 폴더 안에 있는 js 파일들
    • 확장자가 .test.js 인 파일
    • 확장자가 .spec.js 인 파일

    즉 jest는 App.test.tsx파일을 찾아 테스트를 진행하게 될 것입니다. 터미널에서 test를 실행시키는 명령어인 npm test를 실행시키게 되면 jest는 watch mode로 실행이되고 프로젝트에서 위와 조건이 만족하는 파일들을 찾아 모두 실행시킬 겁니다. 한번 npm test를 실행시켜 보겠습니다.

    App.test.tsx에 있는 테스트가 1개가 통과 된 것을 확인 할 수 있습니다.

    React Testing Library

    앞서 jest에 대해 어느정도 알아보았습니다. 하지만 App.test.tsx에서 테스트 코드을 읽다보면 처음보는 함수가 있는데요. 바로 Render입니다.

    test("renders learn react link", () => {
      render(<App />);
      const linkElement = screen.getByText(/learn react/i);
      expect(linkElement).toBeInTheDocument();
    });

    이는 RTL에서 제공하는 함수입니다. 이는 Dom에 컴포넌트를 랜더링하는 함수인데요. 첫 번째로 받아온 컴포넌트를 document.body에 붙혀 넣은 컨테이너로 렌더링합니다. 그 다음 보이는 객체가 하나 있는데요. 바로 screen입니다. 이 객체안에는 쿼리함수들이 제공되는데요. RLT는 쿼리 함수를 제공합니다. 쿼리 함수는 페이지에서 Element를 찾을 수 있는 방법입니다. 말로는 감이 안 올 수 있습니다. 아래에서 더 설명하겠습니다.

    위 예제 코드는 getByText라는 쿼리 함수를 이용하여 <App/> 컴포넌트안에 learn react라는 textContent를 갖는 Element를 찾습니다. 그 다음 expect와 matcher를 통해 테스트를 시도하게 되는데요. toBeInTheDocument라는 matcher는 linkElement가 현재 document안에 존재하는지 체크하게 됩니다. 그럼 실제로 컴포넌트안에 learn react 라는 textContent를 가진 Element가 있을까요?

    // App.tsx
    <a
      className="App-link"
      href="https://reactjs.org"
      target="_blank"
      rel="noopener noreferrer"
    >
      Learn React
    </a>;

    앞서 테스트를 통과한 것으로 볼 때 당연히 존재하고 있습니다 (하하) Learn React는 실제로 에 존재하고 있었고 render 함수를 통해 컴포넌트를 document.body에 붙혀 넣었기 때문에 document 안에는 linkElement가 존재하게 되었고 toBeInTheDocument matcher 함수를 패스해 테스트가 통과하게 된 것입니다. (짜잔)

    쿼리함수의 종류

    쿼리함수의 종류에는 get, find, query가 있스니다. 위에서는 get 형식 (getByText)을 사용 했는데요. get은 일치하는 Element를 가져오다가 Element가 없거나 중복되어 발견된다면 오류를 발생시킵니다. 찾는다면 당연히 일치하는 Elment를 반환합니다. query는 Element를 못찾는다면 null를 반환하고 중복되어 발견 된다면 오류를 발생시킵니다. 찾는다면 당연히 일치하는 Elment를 반환합니다. find의 경우에는 특별(?)한데요. 일치하는 Elment를 발견된다면 Promise 객체를 반환하게 됩니다.

    공통점은 중복되어 발견되면 오류를 발생시킨다는 것입니다. 두 개 이상의 Element를 찾기를 기대한다면 All 키워드를 사용하면 됩니다. 예를 들어 getAllby, queryAllBy, findAllBy 등이 있습니다. 아래의 표를 보면 더욱 쉽게 이해가 가능 할 것입니다.

    정리

    CRA를 통해서 기본적으로 제공된 testcode를 분석하면서 어떻게 돌아가는지 알아보았습니다. 다음 포스팅에선 간단한 앱을 만들면서 테스트하는 방식에 대해 포스팅하겠습니다.

    Refs

    https://create-react-app.dev/docs/running-tests/

    https://testing-library.com/docs/queries/about

    반응형