React 네이티브 애플리케이션의 단위 테스트

게시 됨: 2022-03-10
빠른 요약 ↬ 단위 테스트는 소프트웨어 개발 프로세스의 필수적인 부분이 되었습니다. 소프트웨어 구성 요소가 테스트되는 테스트 수준입니다. 이 튜토리얼에서는 React Native 애플리케이션의 단위를 테스트하는 방법을 배웁니다.

React Native는 모바일 애플리케이션을 구축하기 위해 가장 널리 사용되는 프레임워크 중 하나입니다. 이 튜토리얼은 빌드한 React Native 애플리케이션 테스트를 시작하려는 개발자를 대상으로 합니다. Jest 테스팅 프레임워크와 Enzyme을 사용할 것입니다.

이 기사에서는 테스트의 핵심 원칙을 배우고 애플리케이션 테스트를 위한 다양한 라이브러리를 탐색하며 React Native 애플리케이션의 단위(또는 구성 요소)를 테스트하는 방법을 알아봅니다. React Native 애플리케이션으로 작업함으로써 우리는 테스트에 대한 지식을 확고히 할 것입니다.

참고: JavaScript 및 React Native에 대한 기본 지식은 이 튜토리얼을 진행하면서 큰 도움이 될 것입니다.

단위 테스트 란 무엇입니까?

단위 테스트는 소프트웨어의 개별 구성 요소를 테스트하는 테스트 수준입니다. 각 구성 요소가 예상대로 작동하는지 확인하기 위해 수행합니다. 구성 요소는 소프트웨어에서 테스트할 수 있는 가장 작은 부분입니다.

설명을 위해 Button 구성 요소를 만들고 단위 테스트를 시뮬레이션해 보겠습니다.

 import React from 'react'; import { StyleSheet, Text, TouchableOpacity } from 'react-native'; function AppButton({ onPress }) { return ( <TouchableOpacity style={[styles.button, { backgroundColor: colors[color] }]} onPress={onPress} > <Text style={styles.text}>Register</Text> </TouchableOpacity> ); } const styles = StyleSheet.create({ button: { backgroundColor: red; borderRadius: 25, justifyContent: 'center', alignItems: 'center', }, text: { color: #fff } }) export default AppButton;

Button 구성 요소에는 텍스트와 onPress 기능이 있습니다. 단위 테스트가 무엇인지 알아보기 위해 이 구성 요소를 테스트해 보겠습니다.

먼저 Button.test.js 라는 테스트 파일을 생성해 보겠습니다.

 it('renders correctly across screens', () => { const tree = renderer.create(<Button />).toJSON(); expect(tree).toMatchSnapshot(); });

여기에서는 Button 구성 요소가 애플리케이션의 모든 화면에서 제대로 렌더링되는지 확인하기 위해 테스트하고 있습니다. 이것이 단위 테스트의 모든 것입니다. 응용 프로그램의 구성 요소를 테스트하여 제대로 작동하는지 확인하는 것입니다.

React 네이티브 애플리케이션의 단위 테스트

React Native 애플리케이션은 다양한 도구로 테스트할 수 있으며 그 중 일부는 다음과 같습니다.

  • 웹드라이버
    이 Node.js 앱용 오픈 소스 테스트 도구는 React Native 애플리케이션을 테스트하는 데에도 사용됩니다.
  • 악몽
    이것은 브라우저에서 테스트 작업을 자동화합니다. 문서에 따르면 "목표는 깊이 중첩된 콜백이 아니라 각 스크립팅 블록에 대해 동기적으로 느껴지는 API를 사용하여 사용자 작업(예: goto , typeclick )을 모방하는 몇 가지 간단한 메서드를 노출하는 것입니다."
  • 농담
    이것은 가장 인기 있는 테스트 라이브러리 중 하나이며 오늘 집중할 것입니다. React와 마찬가지로 Facebook에서 유지 관리하며 최대 성능을 위해 "제로 구성" 설정을 제공하도록 만들어졌습니다.
  • 모카
    Mocha는 React 및 React Native 애플리케이션을 테스트하기 위한 인기 있는 라이브러리입니다. 설정 및 사용이 쉽고 빠르기 때문에 개발자가 선택하는 테스트 도구가 되었습니다.
  • 재스민 속
    문서에 따르면 Jasmine은 JavaScript 코드를 테스트하기 위한 동작 중심 개발 프레임워크입니다.
점프 후 더! 아래에서 계속 읽기 ↓

농담과 효소 소개

문서에 따르면 "Jest는 단순성에 중점을 둔 유쾌한 JavaScript 테스트 프레임워크입니다." 제로 구성으로 작동합니다. 설치 시(npm 또는 Yarn과 같은 패키지 관리자 사용) Jest는 다른 설치가 필요 없이 사용할 준비가 됩니다.

Enzyme은 React Native 애플리케이션을 위한 JavaScript 테스트 프레임워크입니다. (React Native가 아닌 React로 작업하는 경우 가이드를 사용할 수 있습니다.) Enzyme을 사용하여 애플리케이션 출력 단위를 테스트합니다. 이를 통해 애플리케이션의 런타임을 시뮬레이션할 수 있습니다.

프로젝트를 설정하여 시작하겠습니다. GitHub에서 Done With It 앱을 사용할 것입니다. React Native 애플리케이션 마켓플레이스입니다. 복제로 시작하고 폴더로 이동한 다음 npm에 대해 다음을 실행하여 패키지를 설치합니다…

 npm install

... 또는 Yarn의 경우:

 yarn install

이 명령은 애플리케이션의 모든 패키지를 설치합니다. 완료되면 아래에서 설명하는 스냅샷을 사용하여 애플리케이션의 UI 일관성을 테스트합니다.

스냅샷 및 Jest 구성

이 섹션에서는 Jest를 사용하여 스냅샷을 테스트하여 사용자 터치와 앱 구성 요소의 UI를 테스트합니다.

그렇게 하기 전에 Jest와 그 종속성을 설치해야 합니다. Expo React Native용 Jest를 설치하려면 다음 명령을 실행합니다.

 yarn add jest-expo --dev

이것은 우리 응용 프로그램의 디렉토리에 jest-expo 를 설치합니다. 다음으로 테스트 스크립트를 갖도록 package.json 파일을 업데이트해야 합니다.

 "scripts": { "test" "jest" }, "jest": { "preset": "jest-expo" }

이 명령을 추가하여 Jest에게 애플리케이션에 등록할 패키지와 위치를 알려줍니다.

다음은 Jest가 포괄적인 테스트를 수행하는 데 도움이 되는 다른 패키지를 애플리케이션에 추가하는 것입니다. npm의 경우 다음을 실행하십시오.

 npm i react-test-renderer --save-dev

... 그리고 Yarn의 경우 다음과 같습니다.

 yarn add react-test-renderer --dev

package.json 파일에는 아직 약간의 구성이 있습니다. Expo React Native의 문서에 따르면 소스 파일이 테스트와 일치할 때마다 Jest에서 테스트가 실행되지 않도록 하는 transformIgnorePattern 구성을 추가해야 합니다(즉, 테스트가 수행되고 프로젝트의 node modules 에서 유사한 파일이 발견되는 경우).

 "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*)" ] }

이제 첫 번째 테스트를 작성하기 위해 App.test.js 라는 새 파일을 만들어 보겠습니다. App 의 트리에 하나의 자식 요소가 있는지 테스트할 것입니다.

 import React from "react"; import renderer from "react-test-renderer"; import App from "./App.js" describe("<App />", () => { it('has 1 child', () => { const tree = renderer.create(<App />).toJSON(); expect(tree.children.length).toBe(1); }); });

이제 yarn test 또는 이에 상응하는 npm을 실행하십시오. App.js 에 단일 자식 요소가 있는 경우 테스트를 통과해야 하며 이는 명령줄 인터페이스에서 확인됩니다.

위의 코드에서 우리는 Expo 에 대한 테스트를 렌더링하는 Reactreact-test-renderer 를 가져왔습니다. 우리는 <App /> 구성 요소 트리를 JSON으로 변환한 다음 Jest에게 JSON에서 반환된 자식 구성 요소 수가 우리가 예상한 것과 같은지 확인하도록 요청했습니다.

추가 스냅샷 테스트

David Adeneye는 다음과 같이 말합니다.

“스냅샷 테스트는 웹 애플리케이션의 사용자 인터페이스(UI)가 예기치 않게 변경되지 않는지 확인합니다. 특정 시점의 구성 요소 코드를 캡처하여 한 상태의 구성 요소를 다른 가능한 상태와 비교할 수 있습니다."

이는 특히 프로젝트에 많은 구성 요소에서 사용되는 전역 스타일이 포함될 때 수행됩니다. UI 일관성을 테스트하기 위해 App.js 에 대한 스냅샷 테스트를 작성해 보겠습니다.

 it('renders correctly across screens', () => { const tree = renderer.create( ).toJSON(); expect(tree).toMatchSnapshot(); }); it('renders correctly across screens', () => { const tree = renderer.create( ).toJSON(); expect(tree).toMatchSnapshot(); });

이것을 우리가 이미 작성한 테스트에 추가한 다음, yarn test (또는 이에 상응하는 npm)를 실행하십시오. 테스트가 통과하면 다음이 표시되어야 합니다.

 PASS src/App.test.js √ has 1 child (16ms) √ renders correctly (16ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 1 total Time: 24s

이것은 우리의 테스트가 통과했고 소요된 시간을 알려줍니다. 테스트를 통과하면 결과가 비슷해 보일 것입니다.

Jest의 일부 기능을 조롱하는 것으로 넘어갑시다.

모의 API 호출

Jest의 문서에 따르면:

모의 함수를 사용하면 함수의 실제 구현을 지우고, 함수에 대한 호출(및 해당 호출에서 전달된 매개변수)을 캡처하고, `new`로 인스턴스화할 때 생성자 함수의 인스턴스를 캡처하고, 테스트를 허용하여 코드 간의 링크를 테스트할 수 있습니다. 반환 값의 시간 구성.

간단히 말해서, 모의 객체는 해당 함수의 실제 작동 없이 객체 또는 함수의 복사본입니다. 그 기능을 모방합니다.

Mock은 다양한 방법으로 앱을 테스트하는 데 도움이 되지만 주요 이점은 종속성에 대한 필요성을 줄여준다는 것입니다.

모의는 일반적으로 두 가지 방법 중 하나로 수행할 수 있습니다. 하나는 테스트할 코드에 주입되는 모의 함수를 만드는 것입니다. 다른 하나는 구성 요소에 연결된 패키지 또는 종속성을 재정의하는 모의 함수를 작성하는 것입니다.

대부분의 조직과 개발자는 기능을 모방하고 가짜 데이터를 사용하여 일부 구성 요소를 테스트하는 수동 모의를 작성하는 것을 선호합니다.

React Native는 전역 객체에 fetch 를 포함합니다. 단위 테스트에서 실제 API 호출을 피하기 위해 이를 조롱합니다. 아래는 React Native에서 의존성 없이 모든 API 호출을 모의(mock)하는 방법입니다.

 global.fetch = jest.fn(); // mocking an API success response once fetch.mockResponseIsSuccess = (body) => { fetch.mockImplementationForOnce ( () => Promise.resolve({json: () => Promise.resolve(JSON.parse(body))}) ); }; // mocking an API failure response for once fetch.mockResponseIsFailure = (error) => { fetch.mockImplementationForOnce( () => Promise.reject(error) ); };

여기에서는 API를 한 번 가져오려고 하는 함수를 작성했습니다. 이렇게 하면 Promise를 반환하고, 해결되면 JSON으로 Body를 반환합니다. 실패한 가져오기 트랜잭션에 대한 모의 응답과 유사하며 오류를 반환합니다.

아래는 product 개체를 포함하고 정보를 props 로 반환하는 애플리케이션의 product 구성 요소입니다.

 import React from 'react'; const Product = () => { const product = { name: 'Pizza', quantity: 5, price: '$50' } return ( <> <h1>Name: {product.name}</h1> <h1>Quantity: {product.quantity}</h1> <h1>Price: {product.price}</h1> </> ); } export default Product;

제품의 모든 구성 요소를 테스트한다고 가정해 보겠습니다. 데이터베이스에 직접 액세스하는 것은 실현 가능한 솔루션이 아닙니다. 이것은 모의가 작동하는 곳입니다. 아래 코드에서 Jest를 사용하여 구성 요소의 개체를 설명하여 제품의 구성 요소를 모의하려고 합니다.

 describe("", () => { it("accepts products props", () => { const wrapper = mount(<Customer product={product} />); expect(wrapper.props().product).toEqual(product); }); it("contains products quantity", () => { expect(value).toBe(3); }); });

우리는 우리가 수행하고자 하는 테스트를 지시하기 위해 Jest의 describe 를 사용하고 있습니다. 첫 번째 테스트에서는 전달하는 객체가 우리가 조롱한 props와 같은지 확인합니다.

두 번째 테스트에서 우리는 customer 소품을 전달하여 그것이 제품이고 우리의 모형과 일치하는지 확인합니다. 그렇게 함으로써 우리는 우리 제품의 모든 구성 요소를 테스트할 필요가 없으며 우리 코드의 버그도 방지할 수 있습니다.

외부 API 요청 모의

지금까지 애플리케이션의 다른 요소를 사용하여 API 호출에 대한 테스트를 실행했습니다. 이제 외부 API 호출을 조롱해 보겠습니다. 우리는 Axios를 사용할 것입니다. API에 대한 외부 호출을 테스트하려면 요청을 조롱하고 받는 응답도 관리해야 합니다. 우리는 Axios를 조롱하기 위해 axios-mock-adapter 를 사용할 것입니다. 먼저 아래 명령을 실행하여 axios-mock-adapter 를 설치해야 합니다.

 yarn add axios-mock-adapter

다음으로 할 일은 모의 객체를 생성하는 것입니다.

 import MockAdapter from 'axios-mock-adapter'; import Faker from 'faker' import ApiClient from '../constants/api-client'; import userDetails from 'jest/mockResponseObjects/user-objects'; let mockApi = new MockAdapter(ApiClient.getAxiosInstance()); let validAuthentication = { name: Faker.internet.email(), password: Faker.internet.password() mockApi.onPost('requests').reply(config) => { if (config.data === validAuthentication) { return [200, userDetails]; } return [400, 'Incorrect username and password']; });

여기에서 ApiClient 를 호출하고 Axios 인스턴스를 전달하여 사용자의 자격 증명을 모의합니다. 우리는 이메일 주소 및 비밀번호와 같은 가짜 사용자 데이터를 생성하기 위해 faker.js라는 패키지를 사용하고 있습니다.

모의는 API가 기대하는 대로 동작합니다. 요청이 성공하면 OK에 대한 상태 코드 200이 포함된 응답을 받게 됩니다. 그리고 서버에 대한 잘못된 요청에 대해 상태 코드 400을 받게 되며, "잘못된 사용자 이름 및 비밀번호" 메시지와 함께 JSON과 함께 전송됩니다.

이제 모의가 준비되었으므로 외부 API 요청에 대한 테스트를 작성해 보겠습니다. 이전과 마찬가지로 스냅샷을 사용할 것입니다.

 it('successful sign in with correct credentials', async () => { await store.dispatch(authenticateUser('[email protected]', 'password')); expect(getActions()).toMatchSnapshot(); }); it('unsuccessful sign in with wrong credentials', async () => { await store.dispatch(authenticateUser('[email protected]', 'wrong credential')) .catch((error) => { expect(errorObject).toMatchSnapshot(); });

여기에서는 입력을 유지하기 위해 기본 JavaScript async await 를 사용하여 올바른 자격 증명으로 성공적인 로그인을 테스트하고 있습니다. 한편 Jest의 authenticateUser 함수는 요청을 인증하고 이전 스냅샷과 일치하는지 확인합니다. 다음으로 이메일 주소나 비밀번호와 같은 잘못된 자격 증명의 경우 로그인 실패를 테스트하고 응답으로 오류를 보냅니다.

이제 yarn test 또는 npm test 를 실행합니다. 나는 당신의 모든 테스트가 통과할 것이라고 확신합니다.

상태 관리 라이브러리인 Redux에서 구성 요소를 테스트하는 방법을 살펴보겠습니다.

스냅샷을 사용하여 Redux 작업 및 감속기 테스트

Redux가 React 애플리케이션에 가장 널리 사용되는 상태 관리자 중 하나라는 것은 부인할 수 없습니다. Redux의 대부분의 기능에는 애플리케이션 상태 변경을 트리거하는 데 사용되는 Redux 저장소의 기능인 dispatch 가 포함됩니다. Redux의 actions 은 크기와 복잡성이 빠르게 증가하기 때문에 Redux를 테스트하는 것은 까다로울 수 있습니다. Jest 스냅샷을 사용하면 이 작업이 더 쉬워집니다. Redux를 사용한 대부분의 테스트는 두 가지로 요약됩니다.

  • actions 을 테스트하기 위해 redux-mock-store 를 만들고 작업을 전달합니다.
  • 리듀서를 테스트하기 위해 reducer 를 가져와 상태와 액션 객체를 전달합니다.

아래는 스냅샷을 사용한 Redux 테스트입니다. SIGN-IN 사용자를 인증하고 user 리듀서에서 LOGOUT 작업을 처리하는 방법을 확인하여 전달된 작업을 테스트할 것입니다.

 import mockStore from 'redux-mock-store'; import { LOGOUT } from '../actions/logout'; import User from '../reducers/user'; import { testUser } from 'jest/mock-objects'; describe('Testing the sign in authentication', () => { const store = mockStore(); it('user attempts with correct password and succeeds', async () => { await store.dispatch(authenticateUser('[email protected]', 'password')); expect(store.getActions()).toMatchSnapshot(); }); }); describe('Testing reducers after user LOGS OUT', () => { it('user is returned back to initial app state', () => { expect(user(testUser, { type: LOGOUT })).toMatchSnapshot(); }); });

첫 번째 테스트에서는 로그인 인증을 설명하고 모의 저장소를 만듭니다. 먼저 Redux에서 mockStore 를 가져온 다음 Jest에서 testUser 라는 메서드를 가져와서 사용자를 조롱하는 데 도움이 됩니다. 다음으로 사용자가 스냅샷 저장소에 있는 것과 일치하는 이메일 주소 및 비밀번호를 사용하여 애플리케이션에 성공적으로 로그인할 때를 테스트합니다. 따라서 스냅샷은 테스트가 실행될 때마다 사용자가 입력하는 개체가 일치하도록 합니다.

두 번째 테스트에서는 사용자가 언제 로그아웃하는지 테스트하고 있습니다. 감속기 스냅샷에서 사용자가 로그아웃했음을 확인하면 애플리케이션의 초기 상태로 돌아갑니다.

다음으로 yarn test 를 실행하여 테스트합니다. 테스트가 통과되면 다음 결과가 표시됩니다.

 PASS src/redux/actions.test.js √ user attempts with correct password and succeeds (23ms) √ user is returned back to initial app state (19ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 2 total Time: 31s

결론

Jest를 사용하면 특히 스냅샷을 사용하여 React Native 애플리케이션을 테스트하는 것이 그 어느 때보다 쉬워졌습니다. 스냅샷을 사용하면 전역 스타일에 관계없이 UI가 일관되게 유지되도록 보장합니다. 또한 Jest를 사용하면 애플리케이션에서 특정 API 호출 및 모듈을 조롱할 수 있습니다. React Native 애플리케이션의 구성 요소를 테스트하여 이를 더 발전시킬 수 있습니다.

추가 리소스

  • "Jest를 사용한 React 네이티브 애플리케이션 테스트에 대한 실용적인 가이드", David Adeneye, Smashing Magazine
  • 농담 문서
  • "Jest로 테스트하기", Expo React Native 문서
  • "Jest로 네이티브 반응 테스트 배우기", Jason Gaare