TIL: RN | TestCode - Jest

Lumpen·2023년 7월 12일
0

TestCode

목록 보기
2/3

페이스북에서는 React Native 어플리케이션을 테스트 하기 위해 Jest 를 사용한다
최신 버전의 React Native (0.38 버전 부터) CRA 에는 Jest 가 기본으로 설치되어 있다

React Native 를 설치하면 package.json 에
다음과 같은 코드가 작성되어 있어야 한다

{
  "scripts": {
    "test": "jest"
  },
  "jest": {
    "preset": "react-native"
  }
}

테스트 구조화

테스트는 짧아야 하고 이상적으로 한 가지만 테스트해야 한다
아마도 함수형 프로그래밍과 잘 어울리지 않을까 싶다

단위 테스트 (unit)

it('given a date in the past, colorForDueDate() returns red', () => {
  expect(colorForDueDate('2000-10-20')).toBe('red');
});

test 는 it 함수에 전달되는 문자열로 설명한다
테스트 중인 항목을 명확하게 설명하는 것에 초점을 맞춰야 한다

AAA (Arrange, Act, Assert)

  1. Given - 주어진 전제조건
  2. When - 테스트 중인 함수에 의해 실행되는 작업
  3. Then - 예상되는 결과

describe

하나의 기능에 속하는 모든 테스트를 그룹화 한다
https://jestjs.io/docs/api

테스트를 분할할 때는 서로 완전히 독립적인지 확인해야 한다
각 테스트는 해당 테스트 자체적으로 실행 가능해야 한다
그리고 서로 영향을 미치지 않아야 한다

단위 테스트

단위 테스트는 개별 함수 또는 클래스 같은 가장 작은 단위에 대해 테스트를 한다
테스트 중인 개체에 종속성이 있는 경우 그것들을 mocking 해야 한다
mocking 은 코드의 일부 종속성을 자체 구현으로 대체하는 것
실제 개체를 사용하기 어렵다면 유용하다

Jest 에는 기능 수준에서 모듈 수준의 모킹까지 지원한다

단위 테스트의 장점은 빠르게 작성하고 실행할 수 있다는 것이다
작업 시 테스트 통과 여부에 대한 빠른 피드백을 받을 수 있고
Jest 에는 편집 중인 코드와 관련된 테스트를 계속 실행하는 옵션도 있다

통합 테스트

소프트웨어 시스템의 개별 부분끼리 상호작용해야 한다
단위 테스트에서 다른 단위에 의존하는 경우 때때로 종속성을 mocking 하여 대체해야 한다

통합 테스트에서는 실제 개별 단위가 결합되고 협력이 예상대로 동작하는지
확인하기 위해 모든 종속성이 함께 테스트 된다
그렇지만 mocking 이 전혀 발생하지 않는 것은 아니다
여전히 몇몇 경우에서는 mocking 이 필요 (예: 날씨 통신 등) 하지만 단위 테스트보다
훨씬 적은 경우에 필요하다

통합 테스트의 의미 또한 항상 같은 범위를 말하는 것은 아니다
단위 테스트와 통합 테스트의 경계가 명확하지 않을 수도 있다
그래도 나눌 수 있는 기준은

  • 여러 모듈을 결합하는 경우
  • 외부 시스템 사용
  • 다른 응용 프로그램 (날씨 api 등) 에 대한 네트워크 호출
  • 모든 종류의 파일 또는 데이터베이스 I/O 수행

컴포넌트 테스트

리액트의 컴포넌트는 앱 렌더링을 담당하며 사용자는 출력과 직접 상호작용 한다
앱의 비즈니스 로직이 정확하더라도 컴포넌트 테스트 없이는 사용자에게 깨진 UI 를
제공할 가능성이 있다
컴포넌트 테스트는 단위 테스트와 통합 테스트에 모두 속할 수 있지만
React Native 의 핵심 기능이므로 별도로 다룬다

  • 상호작용: 사용자가 상호작용할 때 (예: onPress event 등) 구성 요소의 작동 테스트
  • 렌더링: 컴포넌트 렌더링 출력이 올바른지 확인 (UI 모양 및 배치 등)

React 의 테스트 렌더러는 DOM 이나 모바일 환경에 의존하지 않고
React 컴포넌트를 순수한 자바스크립트 객체로 렌더링하는 데 사용할 수 있는 React 렌더러를 제공한다
React Native Testing Library 는 테스트 렌더러 위에 구축되어 컴포넌트 테스트를 할 수 있도록 돕는 라이브러리

컴포넌트 테스트는 Node.js 화경에서 실행되는 JS 테스트일 뿐이다
React Native 컴포넌트를 지원하는 iOS, Android 등의 네이티브 코드는
고려하지 않는다
따라서 테스트가 완벽히 통과하더라도 안전한 코드인지 확신을 줄 수 없다

유저 상호작용 테스트

onPress, onChangeText 등의 이벤트를 테스트할 수 있다
사용자 상호작용 테스트 시에는 사용자 관점에서 컴포넌트를 테스트 해야 한다
페이지에 무엇이 나타나고, 어떤 이벤트에 어떤 변경이 일어나는지

다음과 같은 경우는 피해야 한다

  • making assertions on component props or state
  • testID queries

props 또는 state 같은 구현 세부 사항을 테스트하지 않는다
테스트는 작동하지만 구성 요소와 상호작용하는 방식을 지향하지 않으며
리팩토링으로 중단되는 경향이 있다
함수 컴포넌트를 사용하여 테스트 하는 것이 좋다
구성 요소 내부에 의존하기 더 어려어지기 때문

React Native Testing Library 같은 컴포넌트 테스트 라이브러리는
사용자 중심 테스트 작성을 용이하게 한다

test('given empty GroceryShoppingList, user can add an item to it', () => {
  const {getByPlaceholderText, getByText, getAllByText} = render(
    <GroceryShoppingList />,
  );

  fireEvent.changeText(
    getByPlaceholderText('Enter grocery item'),
    'banana',
  );
  fireEvent.press(getByText('Add the item to list'));

  const bananaElements = getAllByText('banana');
  expect(bananaElements).toHaveLength(1); // expect 'banana' to be on the list
});

호출 시 상태가 어떻게 변경되는지 테스트하지 않는다

스냅샷 테스트

스냅샷 테스트는 예기치 않은 UI 변경을 방지할 때 유용하다
테스트와 함께 스냅샷을 찍어 파일로 저장하고
이전 스냅샷과 비교하여 일치하지 않으면 테스트가 실패한다
새로운 버전으로 스냅샷을 업데이트 하거나
이전 버전과 일치하도록 해야 통과한다

CI 환경에서 스냅샷이 자동으로 작성되지 않는다
모든 스냅샷 파일은 모듈 및 테스트와 함께 커밋되어야 한다
테스트의 일부로 생각해야 한다

스냅샷 테스트는 특정 기능 집합에 대해 단위 테스트를 대체할 수 있지만 함께 사용할 수도 있다

스냅샷은 텍스트 파일에 저장되어 빠르고 안정적이다

항상 해당 파일이 다루는 모듈의 현재 상태로 업데이트 되어야 한다

스냅샷은 설계를 위한 테스트가 아니라
테스트에서 다루고있는 모듈의 변경을 체크하기 위한 것이다

스냅샷 테스트는 고급 유형의 테스트로
매우 강력하고 low level 의 도구이므로 사용 시 각별한 주의가 필요하다

컴포넌트 스냅샷은 Jest 에 내장된 커스텀 React 직렬 변환기에 의해 생성된
JSX 와 유사한 문자열이다
이 직렬 변환기를 사용하면 Jest 각 React 구성 요소 트리를 사람이 읽을 수 있는
문자열로 변환할 수 있다
구성 요소 스냅샷은 테스트 실행 중 생성된 구성 요소의 렌더링 출력을
텍스트로 표현한 것이다

<Text
  style={
    Object {
      "fontSize": 20,
      "textAlign": "center",
    }
  }>
  Welcome to React Native!
</Text>

스냅샷 테스트에서는 먼저 컴포넌트 구현 후 테스트를 진행 한다
스냅샷 텍스트는 스냅샷을 생성하고 저장소 파일에 참조 스냅샷으로 저장한다
저장된 스냅샷은 파일이 커밋되고 코드 검토 중 확인된다
컴포넌트 렌더링 출력에 대한 변경 사항은 해당 스냅샷을 변경하여
테스트가 실패하게 된다
테스트를 통과하려면 참조 스냅샷을 최신으로 업데이트 하던지
변경 사항을 다시 검토하여 참조 스냅샷에 맞게 커밋해야 한다

스냅샷은 몇 가지 단점이 있다

  • 개발자나 리뷰어가 스냅샷의 변경의 의도성을 파악하기 어렵다
    큰 스냅샷은 이해하기 어려어지고 부가 가치가 낮아진다
  • 스냅샷이 생성되면 렌더링 출력이 잘못된 경우에도 해당 시점에서 올바른 것으로 간주된다
  • 스냅샷에 대한 컨벤션이 필요하다

스냅샷은 컴포넌트 렌더링 논리에 대해 확인하지 않으며
예상치 못한 변경을 방지하고 React 트링의 컴포넌트가 예상되는 props 를 수신하는지
확인하는데 유용하다

스냅샷은 작게 사용하는 것이 좋다

엔드 투 엔드 테스트

종단간 테스트에서는 앱이 사용자 관점에서 예상대로 작동하는지 확인한다
릴리즈 구성에 앱을 빌드하고 그에 대한 테스트를 실행하여 수행된다
종단간 테스트에서는 React 컴포넌트, React Native, API 등에 대해 생각하지 안흔ㄴ다

E2E 테스트 라이브러리를 사용하면 앱 화면에서 요소를 찾고 제어할 수 있다
실제 사용자와 같은 방식으로 버튼을 탭하거나 텍스트를 입력할 수 있다
특정 요소가 앱 화면에 존재하는지 여부, 표시 여부, 포함된 텍스트 등에 대해 어설션을 만들 수 있다

E2E 테스트는 앱의 일부 작동에 대해 최고의 신뢰도를 제공하지만 다음과 같은 장단점이 있다

  • 다른 유형 테스트에 비해 많은 시간이 소요된다
  • 실행 속도가 느리다
  • 불안정해지기 쉽다 ("flaky" 테스트는 코드를 변경하지 않고 무작위로 통과하고 실패하는 테스트)

E2E 테스트로는 앱의 중요한 부분 (인증 흐름, 핵심 기능, 결제 등) 을 다루도록 해야한다
상대적으로 덜 중요한 부분들에는 JS 테스트를 사용한다
모든 것을 테스트하지 말고 적절하게 선택하여 배분해야겠다

React Native 커뮤니티에서는 Detox 라이브러리를 제공한다

profile
떠돌이 생활을 하는. 실업자는 아니지만, 부랑 생활을 하는

0개의 댓글