그동안 진행했던 개발 과정에서의 테스팅은 컴포넌트 배치가 적절히 이루어졌는지, 구현이 성공적으로 되었는지를 판단하는 것으로, 실제 앱의 성능이나 최적화 정도를 파악하기 어렵다.
만약 코드를 통한 자동화된 테스팅을 구축하는 경우, 변화에 따라 성능이나 눈으로 파악하지 못한 에러를 미리 미리 파악할 수 있기 때문에 최신 개발 분야에서는 이를 권장하는 편이다.
unit test (단위 테스트) : 함수들에 대해 가장 작은 단위에 대한 테스트, 리액트의 경우 일부 컴포넌트에 대한 테스트, 가장 일반적인 테스트이면서 가장 많이 사용하는 종류의 테스트
intergration test (통합 테스트) : 여러개의 구성 요소의 조합을 테스트, 리액트의 경우 전체 프로젝트 내에서, 컴포넌트 간 상호작용을 테스트 한다. 유닛 테스트 대비 좀 더 큰 범위를 테스트, 프로젝트의 경우 몇몇의 통합 테스트를 사용한다. 그러나 유닛 테스트의 갯수보다 많지 않은 것이 일반적이다.
End-to-End (전구간 테스트) : 어플리케이션의 전체 워크 플로우를 테스트, 실제로 사람이 웹사이트를 방문하여, 모든 서비스와 이벤트를 돌아보면서 진행하는 가장 큰 범위의 테스트이다. 통합 테스트 보다 갯수보다 많지 않은 것이 일반적이며, 보통 유닛 테스트와 통합 테스트가 적절히 이루어지는 경우, 앱이 잘 작동한다고 판단할 수 있으므로 유닛 테스트나 통합 테스트를 더 자주 사용한다.
Jest : 테스팅 코드를 실행하고 결과를 확인하는 데 인기 있는 도구
React testing library : 리액트 앱에서 컴포넌트를 렌더링하고 시뮬레이팅하는 부분에 사용하는 도구
두가지 도구 모두 CRA 를 통해 사용할 수 있도록 설정이 되어있다.
테스트 함수는 총 2개의 인자를 받는다. 첫번째는 테스트에 대한 설명으로 테스트들을 식별하기 위한 용도로 사용되며, 두번째 인자 함수로, 테스트 시 실행할 코드를 받는다.
컴포넌트를 테스트 할 코드를 작성하기 위해서는 해당 컴포넌트 이름에 .test.js를 추가한 파일을 생성한다.
아래의 코드느 App.test.js. 의 예시이다.
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
// 해당 컴포넌트에 learn react 가 있는지를 확인한다.
// (i)는 정규 표현식에서 대소문자를 구분하지 않음을 의미한다.
const linkElement = screen.getByText(/learn react/i);
// 테스트를 하고 그 결과를 터미널에 반환한다.
expect(linkElement).toBeInTheDocument();
});
에러가 나타나느 경우 터미널 창에 이런식으로 어떤 부분이 문제인지를 알려준다. 또한 컴포넌트 변경사항을 감지하고 있어서, 변경사항이 존재하는 경우 바로바로 테스트를 재실행한다.
어플리케이션에 기능이 추가될수록 테스트 코드도 증가하게 될 것이고, 여러 테스트 코드를 그룹화 하기 위해서, describe()
함수를 사용한다. test()
와 동일하게 첫번째 매개변수에는 현재 테스트 카테고리에 대한 설명이 들어가고, 두번째에는 관련 테스트 함수들이 들어간다.
비동기 요청이 필요한 컴포넌트의 경우, find*
함수를 사용하자 find*
함수는 프라미스를 반환한다. 물론 프라미스가 성공적으로 되었을 때의 상태를 보기 위해 async/await
설정을 해주어야 한다.
getBy*
로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 하나를 선택한다. 만약에 없으면 에러가 발생한다.
getAllBy*
로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 여러개를 선택한다. 만약에 하나도 없으면 에러가 발생한다.
queryBy*
로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 하나를 선택한다. 만약에 존재하지 않아도 에러가 발생하지 않는다.
queryAllBy*
로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 여러개를 선택한다. 만약에 존재하지 않아도 에러가 발생하지 않는다.
findBy*
로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 하나가 나타날 때 까지 기다렸다가 해당 DOM 을 선택하는 Promise 를 반환한다. 기본 timeout 인 4500ms 이후에도 나타나지 않으면 에러가 발생한다.
findBy*
로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 여러개가 나타날 때 까지 기다렸다가 해당 DOM 을 선택하는 Promise 를 반환한다. 기본 timeout 인 4500ms 이후에도 나타나지 않으면 에러가 발생한다.
fetch 나 axios 등의 경우 클라이언트로 오는 결과에 대해 테스트를 할 수 있으나, 테스팅 할 때 마다 요청을 보낸다면, 서버가 매 테스트마다 응답결과를 알려줘야 하며, 이는 서버 부하를 일으킨다. 이를 위해, jest 에서는 mock 서버 관련 모의 응답을 가져오도록 설정할 수 있다. 테스팅 함수 작성 시 해당 mock 설정을 통해 가데이터를 가져오는 것으로 대신 api 요청 작업을 테스트하는 것이다.
import { render, screen } from "@testing-library/react";
import Async from "./Async";
describe("Async component", () => {
test("renders posts if request succeeds", async () => {
// Arrange
window.fetch = jest.fn();
window.fetch.mockResolvedValueOnce({
json: async () => [{ id: "p1", title: "First post" }],
});
render(<Async />);
// Act
// ...NOThing
// Assert
const listItemElements = await screen.findAllByRole("listitem");
expect(listItemElements).not.toHaveLength(0);
});
});