react native component Test

악음·2021년 12월 17일
0

jest

목록 보기
5/5
post-thumbnail

이전 포스팅에서는 ts(js)코드를 테스팅하는 방법을 알아보았다
그렇다면 React프론트엔드 개발자라면 당연히 "콤포넌트 테스트는?"이라는 의문을
갖게된다. 그래서 좋은 블로그를 찾아서 파먹어보았다.

참고한 싸이트
달이 차오른다

테스트 함에있어 가장 중요한점

테스트코드의 가장 중요한 요소란 무엇일까?

  1. 잘 짜여진 테스트코드?
  2. 테스트할 필요가 없을정도의 완성도 높은 컴포넌트?
    1,2 모두 아니다.
    테스트 함에 있어서 가장 중요한건 목적이다.

뭐가 궁금해서 테스트를 해야하나? 이것부터 생각을 해봐야할것이다.

화장품업계에 있을때의 테스트

개발업으로 들어서기전 화장품 화학분석을 했었었다.(국내 1위 화장품기업 하하하하하핳하하하하하하하핳)
화학분석의 목적은 무엇일까? 바로 정량/정성 이다.
정량은 얼마만큼 들어있는지 정성은 테스트하고자하는 성분을 정확히 포착했는지 검증하는것이다.
포착하는 방법은

  1. 정량 : 그래프의 크기
  2. 정성 : 그래프가 나타난 시간과 형태

위와같은 목적으로 테스트를 진행한다.

정량을 통해 기능성 물질의 회수률을 구하거나 유해물질이 얼마나 들어있는지 확인할수있다.
즉 테스트를통해 여러가지 결과를 알수있고 이를 검증하는 과정을 거쳐 제품이 출하된다.

개발업계의 테스트

테스트코드도 이와같은 맥락이라고 생각한다.
목적을 명확히 정하고 그 목적을통해 어떤결과를 낼수있을지 생각해보아야한다.
사실 현업에서 테스트코드를 작성해본적은 없다.
이제부터 공부하고 차근차근 적용해보고자한다.

테스트코드 작성

테스트를 진행항 콤포넌트

App.tsx

import React from "react";
import {StyleSheet, View} from "react-native";
import Profile from "./src/Profile";

const App = () => {
  return (
    <View style={styles.container}>
      <Profile userName={"jammie"} name={"ㅇㅈㅅ"} />
    </View>
  );
};

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
});

Profile.tsx

import React, {useState} from "react";
import {StyleSheet, Text, View} from "react-native";
import Greeting from "./Greeting";

const Profile = ({userName, name}: {userName: string; name: string}) => {
  const [msg, setMsg] = useState("Select your status");

  return (
    <View style={styles.container}>
      <Text style={styles.textBox}>
        {userName}({name})
      </Text>
      <Text style={styles.textBox}>{msg}</Text>
      <Greeting title="Bye!" onPress={() => setMsg("Seeya!")} />
      <Greeting title="Hello!" onPress={() => setMsg("Welcome!")} />
    </View>
  );
};

export default Profile;

const styles = StyleSheet.create({
  container: {
    alignItems: "center",
  },
  textBox: {
    marginBottom: 15,
  },
});

Greeting.tsx

import React from "react";
import {Button} from "react-native";

const Greeting = ({title, onPress}: {title: string; onPress: () => void}) => {
  return <Button title={title} onPress={onPress} />;
};
export default Greeting;

테스트의 목적을 살펴보자.

목적 1. App.tsx에서 넘겨준 값이 Profile.tsx에 잘 전달되었는지

목적 2. Profile.tsx에서 greeting.tsx의 버튼을 눌렸을때 값이 잘바뀌는지

목적 3. Greeting에선 Profile에서 넘겨준 값을 잘받았는지

다음 npm을 설치해보자

npm install @testing-library/react-native

테스트를 진행하기전 snapshot을 찍어보자

현재 상태를 스냅샷을 찍어 저장하는 test기능이다.

/**
 * @format
 */

import "react-native";
import React from "react";
// Note: test renderer must be required after react-native.
// https://callstack.github.io/react-native-testing-library/ 여기서 콤포넌트 렌더러확인해보자
import App from "../App";
import {render} from "@testing-library/react-native";

describe("renders correctly", () => {
  test("app renderTest", () => {
    const renderd = render(<App />);
    // 스냅샷 : 해당 콤포넌트의 상태를 백업해놓는다(상태를 임시적으로 저장함)
    // 스냅샷을 찍게되면 테스파일 같은 레벨에 __snapshots__폴더안에 스냅샷 파일을 생성한다.
    // inline스냅샷 : 해당컴포넌트의 상태를 string화시켜서 자동으로 생성해준다(개꿀!)
    // npm run test -u 으로 스탭샷을 다시찍을수있다.(초기화였던가.,.?)
    expect(renderd).toMatchSnapshot();

    // 일단 app.tsx컴포넌트에 대한 스냅샷을 찍어둔다.
    expect(renderd).toBeTruthy();
  });
  // renderer.create(<App />);
});

다음은 처음 설정한 목적에 맞게 테스트를 작성해보자

목적 1

  const willGiveProps = {
    userName: "jammie",
    name: "윤재진",
  };
 test("is print UserName and name of props?", () => {
   // 렌더를 통해 해당 콤퍼넌트의 현재 생태를 가져온다.
    const rendered = render(<Profile {...willGiveProps} />);
   // getBy...을 통해 해당 데이터기있는 엘리먼트를 가져온다.
    let userNameHasElement = rendered.getByText(
      `${willGiveProps.userName}(${willGiveProps.name})`,
    );
    
    console.log(userNameHasElement.props.children);
    // [ 'jammie', '(', '윤재진', ')' ]

    // 어떤값이 있는지 확인(문자 배열안에 어떠한 값이 있는지)
    expect(userNameHasElement.props.children).toContain(willGiveProps.name);
    expect(userNameHasElement.props.children).toContain(willGiveProps.userName);
 });

목적 2

 const willGiveProps = {
    userName: "jammie",
    name: "윤재진",
  };
  test("when onPress Button changed message?", () => {
    const rendered = render(<Profile {...willGiveProps} />);
    // bye 버튼 가져오기
    const byeButton = rendered.getByText("Bye!");
	// hello버튼 가져오기
    const helloButton = rendered.getByText("Hello!");
    // bye button 버튼 누르기
    fireEvent(byeButton, "onPress");
    // 어떤 값을 가져왔는지 확인(값이 없다면 에러가난다)
    rendered.getByText("Seeya!");
    // hellobutton 버튼 누르기
    fireEvent(helloButton, "onPress");
    // 어떤 값을 가져왔는지 확인(값이 없다면 에러가난다)
    rendered.getByText("Welcome!");
  });

fireEvent는 해당 객체의 특정 액션을 실행시키는 함수이다.

목적 3

/**
 * @format
 */
import {fireEvent, render} from "@testing-library/react-native";
import "react-native";
import React from "react";
import Greeting from "../src/Greeting";

describe("greetingComponent recived Props well?", () => {
  // 가짜 함수를 만든다(그냥 이런함수가있다 라는 느낌)
  const onPressMock = jest.fn();
  // 내가 greeting 콤퍼넌트에 넘겨줄 값을 정한다.
  const giveProps = {
    // 타이틀
    title: "Hello!",
    // 넘겨줄 함수
    onPress: onPressMock,
  };
  test("check title Props and onPressButton", () => {
    const rendered = render(<Greeting {...giveProps} />);

    for (let i = 0; i < 5; i++) {
      // 여기서 getBy이란 엘리먼트를 가져온다는 의미이다
      // 즉 내가넘겨준 props.title의 값을 가지고있는 엘리먼트를 가져오고 그엘리먼트를 onPress하겠다는뜻
      // 그리고 onPress는 props.OnPress를 받았다
      fireEvent(rendered.getByText(giveProps.title), "onPress");
    }
    // 위에 for문대로 5번 눌림을 확인
    expect(onPressMock).toBeCalledTimes(5);
  
    // 내가 props으로 던진 값이 정확히 나오는지확인 1을주면 1이 나와야한다
    expect(render.getByText(giveProps.title).props.children).toEqual(giveProps.title);
  });

  // 위에서처럼 props으로 던진 펑션이 5번눌렸는지
  // 위에서 처럼 props으로 던진 title이 잘 전달되었는지 확인할수있다.
});


/**
엘리먼트 펑션 정리
Variant
    getBy* : 조건에 일치하는 엘리먼트를 하나 선택한다. 없다면 테스트 실패로 처리한다.
    getAllBy* : 조건에 일치하는 엘리먼트를 여러개 선택한다. 없다면 테스트 실패로 처리한다.
    queryBy* : 조건에 일치하는 엘리먼트를 하나 선택한다. 존재하지 않아도 실패는 하지 않는다.
    queryAllBy* : 조건에 일치하는 엘리먼트를 여러개 선택한다. 존재하지 않아도 실패는 하지 않는다.
    findBy* : 조건에 일치하는 엘리먼트를 하나 선택한다. 단 Promise 객체를 리턴하며 조건에
    만족하는 엘리먼트가 나타날 때 까지 기다리고 만약 4500ms 내에 발견되지 않으면 테스트는 실패한다.
    findAllBy* : 조건에 일치하는 엘리먼트를 여러개 선택한다. 단 Promise 객체를 리턴하며 조건에 만족하는 엘리먼트가
    나타날 때 까지 기다리고 만약 4500ms 내에 발견되지 않으면 테스트는 실패한다.
Queries( 주로 사용하는 것만 다룸 )
    ByText : 엘리먼트가 가진 텍스트 값으로 선택
    ByAltText : 엘리먼트가 가진 alt 속성으로 선택
    ByTestId : 엘리먼트가 가진 TestId 속성으로 선택
 */
profile
RN/react.js개발자이며 배운것들을 제가 보기위해서 정리하기 때문에 비속어 오타가 있을수있습니다.

0개의 댓글