스무디 한 잔 마시며 끝내는 리액트 + TDD -3장 리액트의 테스트 - Jest

728x90

테스트 코드가 없는 코드를 짜기 싫어하는 나에게 가장 매력적인 파트가 아닐까 싶다. 우테코에서 제작근로를 하면서, Jest, Cypass(?) 등 프론트 진영의 테스트 프레임워크(라이브러리? 프레임워크? 뭐가 맞는 표현일까?)를 언급하는 것을 많이 들어봤지만 한 번도 써본적은 없다.

해당 책에서는 'TDD로 리액트 프로젝트 완성하기'라는 거창한 목표가 있기에 벌써 기대가 되는 파트다.

이번 장에서는 리액트 테스트에 많이 사용되는 자바스크립트 테스트 프레임워크인 Jest에 대해서 살펴보도록 한다.

Jest 공식 홈페이지: https://jestjs.io/

Jest의 장점

Jest는 페이스북에서 개발, 관리하는 js 테스트 프레임워크로써 단순함에 집중한 테스트 프레임워크이다. Jest는 자바스크립트 테스트 프레임워크이므로 리액트 이외에 TypeScript, Node, Angular, Vue 등에서도 사용할 수 있다.
(참고로 이 외에도 자바스크립트의 테스트 프레임워크에는 Mocha, Jasmine, Karma 등이 있다)
리액트에서는 Jest가 특히 많이 사용되고 있다. 리액트의 테스트에 Jest가 많이 상요되는 이유는 리액트를 개발, 관리하는 기업인 페이스북에서 만들었기 때문이고 리액트를 설치하면 기본적으로 Jest도 함께 설치되기 때문이다.

그러나 이런 단순한 이유로 많은 리액트 프로젝트의 테스트에 Jest를 사용하는 것은 아니다. Jest의 장점을 살펴보면서 Jest가 많이 사용되는 이유를 설명한다.

1) 제로 설정

많은 테스트 프레임워크들이 테스트를 하기 위해 많은 설정을 해야 한다. Jest는 이런 설정 때문에 테스트를 쉽게 시작하지 못하고, 테스트에 집중하지 못하는 단점을 보완하기 위해 제로 설정을 지향하고 있다.

2) 스냅샷

테스트하다 보면 값을 일일이 확인하기 힘든 큰 자바스크립트 오브젝트가 존재할 때가 있다. Jest는 이렇게 값 확인이 어려운 큰 오브젝트를 그대로 저장한 후 추후에 값이 변경되면 에러를 표시하는 스냅샷 기능을 제공한다. 리액트에서는 이 스냅샷 기능을 통해 렌더링된 컴포넌트의 변경 사항이 있는지를 체크한다.

3) 모의 객체

Jest는 쉽게 모의 객체(Mocking)를 생성할 수 있다. 이를 통해 테스트 범위를 벗어나는 객체들을 간단하게 모의 객체로 만듦으로써 실제로 테스트해야 할 부분을 집중해서 테스트할 수 있도록 한다.

4) 테스트 코드의 분리

Jest의 테스트 코드는 완전히 분리되어 있으며, 이렇게 분리된 테스트는 동시에 실행할 수 있도록 한다. 따라서 분리된 테스트를 제공하는 Jest는 테스트 코드를 동시에 실행하여 빠른 성능을 제공한다.

5) 간단한 API

Jest는 쉽고 간단하게 테스트할 수 있는 뛰어난 API를 제공하고 있다. 또한, --coverage 옵션을 통해 코드 커버리지(Code, coverage)를 간단하게 확인할 수 있다.

Jest는 페이스북에서 개발, 관리하는 테스트 프레임워크라는 이유뿐만 아니라 이와 같은 장점들 때문에 리액트의 테스트에 많이 사용되고 있다.
(이 책에서는 Jest를 기본으로 리액트 테스트 코드를 작성한다)

프로젝트 준비

자바스크립트 테스트 프레임워크인 Jest를 사용하는 방법에 대해서 살펴보기 위해 간단한 자바스크립트 프로젝트를 생성할 예정이다.

우선 자바스크립트 프로젝트를 위해 폴더를 만든 후에 다음의 명령어를 실행하여 자바스크립트 프로젝트를 준비한다.

cd jest-test
npm init

jest-test 라는 폴더를 만들고 해당 명령어를 실행하였다. 위의 명령어를 실행하면 다음과 같이 package.json을 만들기 위한 질문들이 나오는데 아무것도 입력하지 않고 Enter 키를 눌러 진행한다. (한번만 누르면 되는줄 알았는데, 여러번 눌러야한다...)

image

이게 뭐시여... 약간 당황했지만....

image

당황하지 않고 엔터를 연타 '타타닥'.... 끝

Enter 키를 눌러 진행하였다면 해당 폴더에 package.json이라는 파일이 생성된 것을 확인할 수 있다.

이제 pacakge.json 파일과 같은 위치에 자바스크립트 코드를 추가할 index.js 파일을 생성한다. 이 파일에 테스트 대상이 될 자바스크립트 코드를 작성할 예정이다.

image

나는 갓텔리제이에서 import를 바로 해서 index.js를 생성해줬다!

Jest 설치

이제 자바스크립트 테스트 프레임워크인 Jest를 설치하고 실제로 Jest를 사용하여 테스트하기 위한 준비를 해 보자. 다음의 명령어를 실행하여 Jest를 설치한다.

(해당 명령어는 jest-test폴더에서 실행해야한다)

npm install --save-dev jest

위의 명령어를 실행하면 아래와 같이 뭔가 쭉쭉 다운로드 한다.

image

이렇게 뭔가 다운로드가 완료됐다는 것 같다

image

Jest의 설치가 완료되었다면 package.json 파일을 열어 package.json의 명령어를 모아두는 scripts 부분을 다음과 같이 수정한다.

"scripts": {
  "test": "jest --watch"
},

이제 package.json 파일에 만든 명령어를 실행하기 위해 다음의 명령어를 실행하여 jest를 실행해 보자.

npm run test

우리는 test라는 명령 스크립트에 jest라는 명령어를 --watch 옵션으로 실행하도록 하였다. jest의 watch 옵션은 파일을 감시하고 있다가 파일이 변경되면 해당 파일의 테스트 코드를 다시 실행하기 위한 옵션이다.

명령어가 실행되면 다음과 같은 화면을 볼 수 있다.

Watch Usage
  > Press a to run all tests.
  > Press f to run only failed tests.
  > Press p to filter by a filename regex pattern.
  > Press t to filter by a test name regex pattern.
  > Press q to quit watch mode.
  > Press Enter to trigger a test run.

watch 옵션 때문에 자동으로 테스트가 실행되지만, 위와 같이 터미널에 표시된 키를 눌러 해당 동작을 실행시킬 수도 있다.

이래야 되는데.... 아래와 같은 오류가 발생한다.

image

log로 추가적인 내용을 보라는 거 같으니. 해당 로그로 이동해보자. (vim 명령어로 열어봤다)

image

문제 해결을 위해 참고한 사이트

React "code ELIFECYCLE" Error 해결 (해결 X)

reactjs - TypeError : NPM 테스트를 실행할 때 environment.dispose가 함수가 아닙니다 (O)

참고 사이트에서 git 설정을 초기화하는 git init 명령어를 먼저 실행해보라는 얘기가 있었다. 어려운게 아니니 바로 git init 후 테스트를 실행해보았다.

image

비록 테스트가 깨지긴 하지만, 책에서 소개하는 내용과 동일한 창이 나온다!

사용 방법

자자바스크립트 테스트 프레임워크인 Jest의 사용 방법을 확인하기 위해 package.json 파일이 존재하는 폴더에 index.test.js 파일을 생성하자. Jest는 파일 학장자가 .test.js로 끝나는 파일들을 테스트 파일로써 인식하고 해당 파일을 실행한다. 우리는 이 테스트 파일에 index.js 파일에 관한 테스트를 작성할 것이다.

간단한 함수와 테스트 코드를 작성하여 jest의 사용법을 익혀보도록 하자. index.js 파일을 열어 다음과 같이 수정한다.

image

매우 간단한 함수이다. 이 함수는 a, b 두 개의 매개변수를 받아 더한 결과값을 반환하는 sum 함수이다. Jest를 사용하여 이 함수를 테스트하는 코드를 작성하고 Jest의 사용법을 확인해 보자. Jest의 테스트 파일인 index.test.js 파일을 열어 다음과 같이 수정한다.

image

(와 인생 첫 js 테스트 코드다!! 🎉 감동의 순간)

describe 함수는 Jest가 제공하는 함수로써 여러 테스트를 한 그룹으로 묶고 설명을 붙이기 위해 사용한다. 첫 번째 매개변수는 터미널에 표시할 설명이고, 두 번째 매개변수는 여러 테스트를 그룹으로 묶을 콜백(Callback) 함수이다.

Jest가 제공하는 it 함수는 실제 테스트가 실행되는 테스트 명세를 작성할 때 사용한다. 첫 번째 매개변수테스트명세의 설명두 번째 매개변수에는 실제로 테스트를 실행하는 테스트 코드를 작성한다.

우리는 npm run test로 Jest가 파일을 감시하고 있다가 변경되면 테스트를 다시 실행하도록 jest --watch 명령어를 실행해 두었기 때문에 위와 같이 파일을 작성하고 저장하면 Jest가 파일의 변경을 감지하고 자동으로 테스트 코드를 실행한다. 따라서 터미널에 다음과 같은 화면을 확인할 수 있다. (사진의 터미널 창을 확인하면 된다!)

여기서 우리는 변경돈 ./index.test.js 파일이 실행되었음을 알 수 있다.

index.js 파일을 열어 다음과 같이 수정하여 테스트에 실패하도록 만들어 보자.

image

테스트가 실패하면 실패한 테스트 명세(it 함수 내용) 앞에 체크가 아닌 엑스가 표시되고 실패한 내용이 자세히 나오는 것을 확인할 수 있다.

Matcher

우리는 앞의 사용법 절에서 toBe라는 Matcher를 사용하여 테스트 코드를 작성했다. Matcher는 Jest가 제공하는 함수로써 결과값을 비교하여 테스트의 성공 여부를 판단할 때 사용한다. 여기서는 Jest에서 자주 사용되는 Matcher를 소개한다.

1) toEqual

toEqual은 오브젝트(Object)를 비교할 때 사용되는 Matcher이다. toEqual의 사용법을 확인하기 위해 index.js를 다음과 같이 수정한다.

image

person 함수는 이름(name)과 나이(age) 매개변수를 전달받아 person 오브젝트를 반환하는 함수이다. 이제 index.test.js 파일을 열어 다음과 같이 수정한다.

(꿀Tip: 인텔리제이를 쓴다면, command + N 을 누른 뒤, 아래의 키를 누르면 테스트 케이스를 자동으로 생성해준다)

image

자바스크립트에서는 오브젝트의 내용이 같아도 다른 값으로 인식한다. 따라서, 단순히 person 함수를 통해 생성한 값과 toEqual에서 사용한 값을 단순히 비교(===)하면 다른 값이라고 판단하게 된다. 이와 같은 문제가 있으므로 Jest에서 오브젝트를 테스트할 때는 toEqual을 사용하여 위와 같이 테스트한다. 만약 이곳에서 toBe를 사용하면 단순히 값을 비교하므로 에러가 발생하며 테스트를 통과하지 못한다.

이렇게 파일을 수정하고 수정한 파일들을 저장하면 우리가 실행한 명령어에 의해 테스트 코드가 자동으로 실행되면 다음과 같이 성공적으로 테스트가 실행되었음을 확인할 수 있다.

2) toBeTruthy, toBeFalsy

toBeTruthy와 toBeFalsy는 참 / 거짓 값(Boolean)을 체크할 때 사용하는 Matcher이다. toBeTruthy와 toBeFalsy를 사용하여 테스트하기 위해 index.js 파일을 열어 다음과 같이 수정한다. (사진은 그만 첨부하는걸로 하자!)

const toggle = (a) => {
  return !a;
};

module.exports = {
  ...
  toggle,
};

toggle 함수는 전달받은 매개변수의 반대값을 반환하는 간단한 함수이다. 이제 Jest의 toBeTruthy, toBeFalsy를 사용하여 toggle 함수를 테스트하기 위해 index.test.js 파일을 열어 다음과 같이 수정한다.

const { ..., toggle } = require('./index');

describe('test index.js file', () => {
  ...
  it('return false', () => {
    expect(toggle(true)).toBeFalsy();
    expect(toggle(false)).toBeTruthy();
  });
});

우리가 만든 toggle 함수에 참값(true)을 매개변수로 전달하였고 우리가 결과값으로 예상하는 값인 거짓값을 확인하기 위해 toBeFalsy를 사용한 것을 확인할 수 있다. 또한, not과 toBeTruthy를 사용하여 반환된 값이 참이 아님으르 확인했다.

이렇게 파일을 수정하고, 수정한 파일들을 저장하면 Jest가 수정된 테스트 파일을 실행하고 명령 프롬프트에 다음과 같이 테스트가 성공했음을 표시한다.

3) toContain

Jest에서는 배열(Array)에 특정값이 포함되어 있는지를 확인할 때 toContain을 사용한다. Jest의 toContain을 사용하여 배열값을 확인하기 위해 index.js 파일을 열어 다음과 같이 수정한다.

...
const range = (start, end) => {
  let result = [];
  for (let i = start; i <= end; i++) {
    result.push(i);
  }
  return result;
};

module.exports = {
  ...
  range,
}

range 함수는 배열에 시작과 끝값을 전달받아서 배열을 만들어 반환하는 함수이다. Jest의 toContain을 사용하여 이 함수를 테스트하기 위해 index.js 파일을 열어 다음과 같이 수정한다.

const { ..., range } = require('./index');

describe('test index.js file', () => {
  ...
  it('has 2', () => {
    expect(range(1, 3).toContain(2));
  });
});

toContain을 사용해서 1로 시작하여 3으로 끝나는 배열에 2가 포함되어 있는지 확인하는 테스트 코드를 작성하였다.

이렇게 파일을 수정하고, 수정한 파일을 저장하면 다음과 같이 모든 테스트가 성공적으로 실행됨을 확인할 수 있다.

4) 기타

이 밖에도 Jest에는 많은 Matcher가 존재한다. 다음 링크에서 Jest에서 사용 가능한 다른 Matcher를 확인할 수 있다. 앞으로 Jest를 사용하여 계속 테스트할 예정이므로 아래 링크를 한 번 방문하여 어떤 Matcher가 존재하는지 확인해 보길 권장한다.

코드 커버리지

테스트에서 코드 커버리지(Code coverage)란 테스트 대상이 되는 소스 코드 중 테스트 코드를 통해 검증된 코드의 비율을 의미하며, 테스트 수행 결과를 정량적으로 나타내는 수치이다.

코드 커버리지를 통해 테스트 코드가 얼마나 많은 소스 코드를 테스트하고 있는지 나타내는 중요한 지표이다. 이 지표를 통해 우리는 테스트 코드가 작성되지 않은 코드를 확인할 수 있다.

Jest에서는 다음의 명령어를 통해 간단하게 코드 커버리지를 확인할 수 있다.
npx test --coverage

우리가 앞서 테스트 코드를 작성한 폴더에서 위 명령어를 실행해 보면 다음과 같은 결과를 얻을 수 있다.

image

이렇게 Jest의 코드 커버리지를 통해 우리가 실제로 사용하는 코드에 대한 테스트 코드가 얼마나 많이 작성되어 있는지, 작성되어 있지 않은 부분은 어디인지 한눈에 확인할 수 있다.

728x90