출시·고도화 중
React Native 안내서 · 5/6
React Native 앱은 보통 세 층으로 테스트합니다. 순수한 로직은 Jest로, 컴포넌트는 React Native Testing Library로, 실제 기기에서 사용자 흐름 전체는 Detox나 Maestro 같은 E2E 도구로 검사합니다.
| 층 | 도구 | 실행 환경 |
|---|---|---|
| 단위 | Jest | Node.js |
| 컴포넌트 | Jest + React Native Testing Library | Node.js(네이티브 없이 렌더링) |
| E2E | Detox, Maestro | 에뮬레이터·시뮬레이터·실기기 |
Community CLI 템플릿에는 react-native 프리셋으로 설정된 Jest가 이미 들어 있습니다. Expo 프로젝트에서는 jest-expo 프리셋을 추가합니다.
npx expo install jest-expo jest @types/jest -- --dev
npx expo install @testing-library/react-native -- --dev{
"scripts": {
"test": "jest --watchAll"
},
"jest": {
"preset": "jest-expo"
}
}프리셋은 React Native 모듈의 모의 구현과 변환 설정을 제공하므로, 테스트 파일(*.test.tsx 또는 __tests__ 폴더)만 만들면 됩니다.
화면과 상관없는 계산·변환 로직은 일반 Jest 테스트로 검사합니다. 로직을 컴포넌트 밖 함수로 빼 두면 테스트하기 쉬워집니다.
// price.ts
export const formatPrice = (won: number) => `${won.toLocaleString("ko-KR")}원`;
// price.test.ts
import { formatPrice } from "./price";
test("천 단위 구분 기호를 붙인다", () => {
expect(formatPrice(12000)).toBe("12,000원");
});React Native Testing Library(RNTL)는 컴포넌트를 렌더링한 뒤 사용자가 보는 글자나 접근성 역할로 요소를 찾고, 누르기·입력 같은 동작을 흉내 냅니다. 구현 세부보다 사용자가 보는 결과를 검사하는 것이 원칙입니다.
import { render, screen, userEvent } from "@testing-library/react-native";
import { Counter } from "./Counter";
test("누르면 숫자가 올라간다", async () => {
const user = userEvent.setup();
render(<Counter />);
expect(screen.getByText("Count: 0")).toBeOnTheScreen();
await user.press(screen.getByText("Increment"));
expect(screen.getByText("Count: 1")).toBeOnTheScreen();
});toBeOnTheScreen, toHaveTextContent 같은 매처는 RNTL이 제공합니다. 오래된 버전에서는 설정 파일에서 @testing-library/react-native/extend-expect를 불러와야 할 수 있습니다. 조회 함수는 getBy...(즉시, 없으면 오류), queryBy...(없으면 null), findBy...(나타날 때까지 기다림)로 나뉩니다.
네트워크나 네이티브 모듈은 테스트에서 모의 객체로 바꿉니다. AsyncStorage는 공식 Jest 모의 구현을 제공합니다.
import { render, screen } from "@testing-library/react-native";
import { Posts } from "./Posts";
jest.mock("@react-native-async-storage/async-storage", () =>
require("@react-native-async-storage/async-storage/jest/async-storage-mock"),
);
test("서버에서 받은 글을 보여 준다", async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: async () => [{ id: 1, title: "첫 글" }],
}) as jest.Mock;
render(<Posts />);
expect(await screen.findByText("첫 글")).toBeOnTheScreen();
});E2E 테스트는 실제로 빌드한 앱을 에뮬레이터나 기기에서 실행해 사람이 쓰듯 조작합니다. 요소를 찾기 쉽도록 컴포넌트에 testID를 붙여 둡니다.
Detox는 Wix가 만든 그레이박스 E2E 프레임워크입니다. 앱 내부의 네트워크 요청·애니메이션이 끝날 때까지 자동으로 기다리므로 테스트가 덜 흔들립니다. 테스트는 JavaScript로 쓰고 Jest로 실행합니다. 설정은 .detoxrc.js에 두며, Expo 프로젝트는 개발 빌드나 prebuild로 네이티브 프로젝트를 만든 뒤 씁니다.
describe("로그인", () => {
beforeAll(async () => {
await device.launchApp();
});
it("로그인하면 홈 화면이 보인다", async () => {
await element(by.id("email")).typeText("user@example.com");
await element(by.id("login-button")).tap();
await expect(element(by.text("Welcome"))).toBeVisible();
});
});npx detox build --configuration ios.sim.debug
npx detox test --configuration ios.sim.debug설정 이름(ios.sim.debug 등)은 .detoxrc.js에서 정한 것입니다.
Maestro는 YAML로 흐름을 적는 블랙박스 E2E 도구입니다. 앱 코드를 고치지 않고 설치된 앱을 바깥에서 조작하므로 설정이 간단하며, EAS Workflows에서도 실행할 수 있습니다. React Native의 testID는 Maestro에서 id로 찾습니다.
appId: com.example.myapp
---
- launchApp
- tapOn:
id: "email"
- inputText: "user@example.com"
- tapOn: "Log in"
- assertVisible: "Welcome"maestro test .maestro/login.yamljest-expo 프리셋)와 React Native Testing Library로 씁니다.userEvent로 동작을 흉내 냅니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.