테스트 코드는 리팩토링의 안전망이며, 면접에서 "테스트를 작성해본 경험"은 큰 가산점입니다.


설치

BASH
npm install -D jest @testing-library/react-native @testing-library/jest-native

컴포넌트 테스트

TSX
// components/Counter.tsx
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <View>
      <Text testID="count-text">{count}</Text>
      <Pressable testID="increment-btn" onPress={() => setCount((c) => c + 1)}>
        <Text>+1</Text>
      </Pressable>
    </View>
  );
}

// __tests__/Counter.test.tsx
import { render, fireEvent, screen } from '@testing-library/react-native';
import Counter from '../components/Counter';

describe('Counter', () => {
  it('초기값이 0이다', () => {
    render(<Counter />);
    expect(screen.getByTestId('count-text')).toHaveTextContent('0');
  });

  it('버튼을 누르면 카운트가 증가한다', () => {
    render(<Counter />);
    fireEvent.press(screen.getByTestId('increment-btn'));
    expect(screen.getByTestId('count-text')).toHaveTextContent('1');
  });
});

비동기 테스트

TSX
import { render, waitFor, screen } from '@testing-library/react-native';

// API를 호출하는 컴포넌트 테스트
jest.mock('../api/userApi', () => ({
  getUsers: jest.fn(() => Promise.resolve([
    { id: '1', name: '홍길동' },
    { id: '2', name: '김철수' },
  ])),
}));

it('사용자 목록을 로드하여 표시한다', async () => {
  render(<UserList />);

  // 로딩 상태 확인
  expect(screen.getByTestId('loading')).toBeTruthy();

  // 데이터 로드 완료 대기
  await waitFor(() => {
    expect(screen.getByText('홍길동')).toBeTruthy();
    expect(screen.getByText('김철수')).toBeTruthy();
  });
});

커스텀 Hook 테스트

TSX
import { renderHook, act } from '@testing-library/react-native';

function useCounter(initial = 0) {
  const [count, setCount] = useState(initial);
  const increment = () => setCount((c) => c + 1);
  const reset = () => setCount(initial);
  return { count, increment, reset };
}

describe('useCounter', () => {
  it('초기값으로 시작한다', () => {
    const { result } = renderHook(() => useCounter(5));
    expect(result.current.count).toBe(5);
  });

  it('increment 호출 시 카운트가 증가한다', () => {
    const { result } = renderHook(() => useCounter());
    act(() => result.current.increment());
    expect(result.current.count).toBe(1);
  });
});

네비게이션 테스트

TSX
import { NavigationContainer } from '@react-navigation/native';
import { render, fireEvent, screen } from '@testing-library/react-native';

// 네비게이션 래퍼
function renderWithNavigation(component: React.ReactElement) {
  return render(
    <NavigationContainer>{component}</NavigationContainer>
  );
}

it('상세 화면으로 이동한다', () => {
  renderWithNavigation(<AppNavigator />);
  fireEvent.press(screen.getByText('상세 보기'));
  expect(screen.getByText('상세 화면')).toBeTruthy();
});

정리

  • testID 를 사용하면 구현과 분리된 안정적인 테스트를 작성할 수 있습니다
  • ** 비동기 테스트 **는 waitFor를 사용하여 상태 변화를 기다립니다
  • 네이티브 모듈은 jest.mock() 으로 모킹합니다
  • 테스트는 ** 사용자 행동 기준 **으로 작성하세요 — 내부 구현이 아닌 결과를 검증합니다
  • 커스텀 Hook은 renderHook으로 독립적으로 테스트할 수 있습니다
댓글 로딩 중...