내 사이드 프로젝트 중 운동 어플 '헛둘'에 테스트 코드를 작성해보려고 한다. 타이머를 밀리세컨드 단위로 조작하다 보니 예상치 못한 버그 방지에도 좋을 것 같다는 생각이 들었다.
툴은 가장 많이 쓰이는 Jest와 React Native Testing Library를 사용하려고 한다.
Jest
메타(구 페이스북)에서 관리하는 Javascript의 테스트 러너이다.
웹에서는 jsdom을 사용하지만, 모바일에서는 네이티브 모바일 환경을 재현하는 방식으로 사용한다. DOM이나 브라우저 API를 로딩하지 않아 실행 시간이 더 줄어든다.
jsdom: Node.js 내에서 실행되는 가벼운 브라우저 (가상의 Dom)
Jest는 React Native 프로젝트를 생성하면 package.json 파일에 자동으로 생성되어 있다.
React Native Testing Library
React Testing Library에서 영감을 받은 React Native용 테스트 라이브러리이다.
사용자의 관점에서 UI와의 상호작용을 중심으로 테스트를 진행한다.
RNTL은 사용자 중심의 테스트를 한다. 컴포넌트 내부 구현을 위한 테스트를 하고 싶다면 Enzyme 라이브러리를 사용할 수도 있다.
Enzyme: 컴포넌트의 내부 구현을 더 세밀하게 테스트할 수 있는 기능을 제공
@testing-library/jest-native 패키지를 같이 사용한다.
: React Native를 위한 Jest 확장 라이브러리.
: React Native 컴포넌트를 테스트할 때 사용할 수 있는 추가적인 Jest matchers를 제공한다.
# yarn
yarn add --dev @testing-library/react-native
yarn add --dev @testing-library/jest-native
# npm
npm install --save-dev @testing-library/react-native
npm install --save-dev @testing-library/jest-native
패키지 설치 후 아래와 같이 설정해 준다.
jest-setup.ts
import '@testing-library/jest-native/extend-expect';
import '@testing-library/react-native/extend-expect';
테스트 유형
단위 테스트 (Unit Testing):
단위 테스트는 애플리케이션의 가장 작은 단위(함수, Class, 컴포넌트)가 예상대로 올바르게 작동하는지 확인하는 것이다.
데이터베이스, 파일시스템 등과 같은 외부 시스템과의 종속성과 분리해서 진행한다.
- 운동 시작, 설정 버튼 등이 제대로 표시되는지 확인한다.
- '연속 운동 추가' 버튼을 클릭 시 운동이 추가되는지 테스트한다.
통합 테스트 (Integration Testing):
통합 테스트는 여러 개의 단위(Unit)가 함께 잘 작동하는지 확인하는 테스트이다.
통합 테스트와 E2E 테스트는 데이터베이스, 파일 시스템, 외부 API 등과 같은 외부 시스템을 포함하기도 하지만, 테스트 환경에서 실제 외부 시스템을 사용하는 것이 어렵거나 비효율적일 수도 있다. 그래서 이런 상황에서는 모킹(Mocking)이라는 기술을 사용한다.
Mocking: 외부 시스템을 가상의 객체나 서비스로 대체하여, 테스트를 더 간편하고 빠르게 진행할 수 있도록 합니다.
- 설정 완료 버튼을 클릭 시 각 운동 종류마다 데이터가 저장 됐는지 확인한다.
- 운동 설정 각 탭마다 운동 데이터가 표시되는지 확인한다.
E2E (End-to-End) 테스트:
E2E 테스트는 사용자의 관점에서 애플리케이션의 전체 흐름을 검증하는 과정이다. 사용자가 실제로 애플리케이션을 사용하는 방식을 모방하여, 시작부터 끝까지의 전체 과정을 검증한다.
- 사용자가 운동 시작을 누르면 준비 -> 운동 중 -> 쉬는 시간 페이지 순으로 이동한다.
- 운동 설정에서 설정한 데이터가 운동시작 시 제대로 반영 됐는지 확인한다.
위 세 유형의 테스트를 다양하게 잘 조합해서 사용하도록 하자.
Given When Then 전략
Given When Then 전략은 테스트 케이스를 작성하는 데 사용되는 방법론이다. 작성한 테스트 코드의 구조를 명확하고 이해하기 쉽게 하기 위함이다.
Given (준비 단계):
테스트에 필요한 객체를 초기화하고, 필요한 데이터를 설정한다.
When (실행 단계):
테스트의 행동을 실행한다.
Then (검증 단계):
실행한 행동의 결과가 예상과 일치하는지 검증한다
test('should return 3 when 1 and 2 are added', () => {
// given
const a = 1;
const b = 2;
// when
const result = plus(a, b);
// then
expect(result).toBe(3);
});
test 명칭 가이드:
Should [예상되는 결과] when [특정 조건이나 상황]
이렇게 작성하면 테스트 코드의 가독성이 향상되고, 다른 개발자들이 코드를 더 쉽게 이해할 수 있게 된다.