본문 바로가기
모바일 APP/React-Native

Testing - 컴포넌트 테스트

by 살길바라냐 2023. 2. 6.

React 컴포넌트는 app redering이 담당한다.
그리고 사용자가 직접적으로
React 컴포넌트의 산출물과 상호작용한다. 

앱의 비즈니스 로직이 테스트 범위가 높고
정확한 경우

컴포넌트 테스트 없이도
사용자 UI가 손상될 수 있습니다.

컴포넌트 테스트는 단위와 통합 텓스트
모두에 해당 될수 있지만,

React Native의 핵심 부분이기 때문에
별도로 다뤄야 한다. 

 

 

react component를 테스트하기 위해
다음 두 가지를 테스트할 수 있습니다

1. 상호작용(Interaction) : 

사용자와 상호 작용할 때(예: 사용자가 버튼을 누를 때)
component가 올바르게 작동하는지 확인한다.

2. 렌더링(Rendering) :

React에서 사용하는 component
렌더 출력이 올바른지 확인합니다(예: UI에서 버튼 모양 및 배치)

 

가령 버튼이 가지고 있는 onPress 리스너를 
테스트 한다고 할때

정확히 나타나는지, 탭이 정확히 컴포넌트로
작동하는지 테스트가 가능하다. 

 

대표적으로 지원하는 2가지 
라이브러리가 있다

1.Test Renderer, :

코어와 함께 개발된 리액트 렌더러는 DOM이나
네이티브 모바일 환경에 의존하지 않고
리액트 구성 요소를 순수 자바스크립트 객체로
렌더링하는 데 사용할 수 있다.

2.React Native Testing Library :

위 라이브러리 React의 테스트 렌더러를 사용하며
fireEvent 및 쿼리 API를 추가적으로 사용 가능하다. 

 

!!! 주의

component 테스트는 Node.js 환경에서 실행되는
JavaScript 테스트일 뿐이다.

이들은 리액트 네이티브 컴포넌트를 지원하는 iOS, 안드로이드
또는 기타 플랫폼 코드를 고려하지 않는다.

따라서 모든 것이 사용자에게 효과가 있다는 100% 확신을 줄 수 없다.
만약 iOS나 안드로이드 코드에 버그가 있다면,

찾지 못할 것이다.

 

- 사용자 상호작용 테스팅

onChangeText, TextInut, 버튼 onPress 같은
다른 함수가 포함되거나, event callback 이
포함된 컴포넌트를 테스트를 하려면

1. 경험적으로 사용자가 보거나
들을 수 있는 내용을 사용하는 것을 선호합니다 :

 

2. 반대로 아래 사항은 피한다:

  • component props 또는 state에 표시
  • testID queries

 

props이나 state와 같은 실행 세부사항을
테스트하지 말아라.

이러한 테스트는 사용자가 구성요소와 상호작용하는 방식을
지향하지 않으며

리팩토링(예: 일부 항목의 이름을 바꾸거나 hook 사용하여 class component를 다시 작성하려는 경우)
을 통해 멈추는 경향이 있다.

 

!!!주의

react class component 는 특히 내부 state,
Props 또는 이벤트 핸들러와 같은 실행 세부사항을 테스트하는 경향이 있다.

이런 세부사항 테스트를 피하려면,
hooks을 이용한 함수형 component를 사용해서
component가 내부적으로 의존하는것 더 어렵게 만든다.

React Native Testing Library와 같은 기능은
component 테스트 라이브러리는
제공된 API를 신중하게 선택하여
사용자 중심 테스트가 용이하다.

예를 들면 fireEvent 메소드는 changeTextpress
component와 query function으로 
사용자와 상호작용 하는것처럼 가정하는게 가능하다.

getAllByText는 reder된 산출물에서
Text 컴포넌트들 중에 매칭된 것을 찾는다.

 

test('빈 GroceryShoppingList 줘, 사용자는 GroceryShoppingList에 항목울 추가 할수 있다.', () => {
  const {getByPlaceholder, getByText, getAllByText} = render(
    <GroceryShoppingList />,
  );

  fireEvent.changeText(
    getByPlaceholder('식료품 항목 입력'),
    'banana',
  );
  fireEvent.press(getByText('list로 항목 추가'));

  const bananaElements = getAllByText('banana');
  expect(bananaElements).toHaveLength(1); // 'banana' 글자가 나올꺼라 기대
});

 

위 예제는 함수 호출시 state 변경에 관련된 테스트 아니다.
사용자가 Text Input과 Button을 눌러 text를 변경 했을때
어떤일이 일어나는지에 대한 테스트 이다. 

 

- 렌더된 산출물 테스팅

Snapshot testing 는 Jest로 테스팅 하는 고급 기술이란다...
매우 강력한 low level의 도구이므로 
사용시 더 각별한 주의가 필요하다.

"component snapshot"은 Jest에 내장된
custom React serializer에 의해 생성된 JSX와 같은 문자열이다.

serializer는 Jest가
React component 트리 -> 사람이 읽을 수 있는 string으로 변환 해준다.

다른말로 하자면: component snapshot은 
테스트를 실행하는 동안  component의 렌더로
산출물로 발생한 텍스트 표현 이다. 

아래와 같이 생성 될거다.

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`[App] render renders without crashing 1`] = `
<View
  style={
    Object {
      "alignItems": "center",
      "flex": 1,
      "justifyContent": "center",
    }
  }
>
  <View
    style={
      Object {
        "alignItems": "center",
      }
    }
  >
    <Text
      style={
        Object {
          "marginBottom": 15,
        }
      }
    >
      samslow
      (
      서현석
      )
    </Text>
    <Text
      style={
        Object {
          "marginBottom": 15,
        }
      }
    >
      Select your status
    </Text>
    <View
      accessibilityRole="button"
      accessible={true}
      collapsable={false}
      focusable={true}
      onClick={[Function]}
      onResponderGrant={[Function]}
      onResponderMove={[Function]}
      onResponderRelease={[Function]}
      onResponderTerminate={[Function]}
      onResponderTerminationRequest={[Function]}
      onStartShouldSetResponder={[Function]}
      style={
        Object {
          "opacity": 1,
        }
      }
    >
      <View
        style={
          Array [
            Object {},
          ]
        }
      >
        <Text
          style={
            Array [
              Object {
                "color": "#007AFF",
                "fontSize": 18,
                "margin": 8,
                "textAlign": "center",
              },
            ]
          }
        >
          Bye!
        </Text>
      </View>
    </View>
    <View
      accessibilityRole="button"
      accessible={true}
      collapsable={false}
      focusable={true}
      onClick={[Function]}
      onResponderGrant={[Function]}
      onResponderMove={[Function]}
      onResponderRelease={[Function]}
      onResponderTerminate={[Function]}
      onResponderTerminationRequest={[Function]}
      onStartShouldSetResponder={[Function]}
      style={
        Object {
          "opacity": 1,
        }
      }
    >
      <View
        style={
          Array [
            Object {},
          ]
        }
      >
        <Text
          style={
            Array [
              Object {
                "color": "#007AFF",
                "fontSize": 18,
                "margin": 8,
                "textAlign": "center",
              },
            ]
          }
        >
          Hello!
        </Text>
      </View>
    </View>
  </View>
</View>
`;

snapshot으로 테스팅,
일반적으로 먼저 component를 구현한 다음
스냅샷 테스트를 실행한다.

snapshot 테스트 한다음  snapshot 생성 및 저장된다.
snapshot 참조처럼 너의 저장소로 

파일이  코드 검토 중에  커밋되고 확인됩니다 .

component render 출력을 나중에 변경하면
snapshot이 변경되어 테스트가 실패한다.

테스트를 통과하려면 저장된 참조 스냅샷을
업데이트해야 한다.

변경후 다시 committed 및 reviewed 필요하다.

 

snapshots의 몇가지 단점이 있다.:

- 개발자 또는 검토자인 경우 snapshot의 변경이
의도된 것인지 또는 버그의 증거인지 구별하기 어려울 수 있다.
특히 큰 snapshot은 빠르게 이해하는게 어려울수 있다. 

- snapshot이 생성되면 렌더링된 출력이
실제로 잘못된 경우에도
해당 시점에서 올바른 것으로 간주된다.

- snapshot 실패시, 변경이 예상되는지 여부를 조사하기 위해
충분한 주의를 기울이지 않고 --updateSnapshot jest 옵션을
사용하여 업데이트하려고 한다.
따라서  개발자 규율이 필요하다.
 

 

 

Snapshot은 component logic이
정확한지에 대한 확신이 없다.

예상치 못한 변화를 방지하고
테스트 대상인 React tree의 component가
예상되는 Pops(styles 등)을 수신하는지 확인하는 데만
능숙하다.

작은 snapshots 사용하기를 무조건 추천한다. (see no-large-snapshots rule).
서로 다른 React component states 변화를 테스트를 원하면, snapshot-diff 사용하면 된다.

728x90
반응형

'모바일 APP > React-Native' 카테고리의 다른 글

Testing - 통합 테스트  (0) 2023.02.06
Testing - 단위 테스트  (0) 2023.02.06
Testing - 테스트 쓰기  (0) 2023.02.06
Testing - 테스트 가능한 코드 쓰기  (0) 2023.02.06
Testing - 정적 분석  (0) 2023.02.06