테스트
애플리케이션의 품질과 안전성을 높이기 위해 사전에 결함을 찾아내고 수정하는 행위
테스트 코드의 효과
올바른 테스트 작성 규칙
단위 테스트
단일 함수의 결과값 또는 단일 컴포넌트의 상태(UI)나 행위를 검증
공통 컴포넌트는 단위 테스트에 적합 (다른 컴포넌트와 상호작용이 없고 내부 비즈로직을 기능 단위로 검증하기 좋다.)
setup과 teardown
setup: 테스트를 실행하기 전 수행해야 하는 작업
teardown : 테스트를 실행한 뒤 수행해야 하는 작업
React Testing Library의 핵심 철학
UI 컴포넌트를 사용자가 사용하는 방식으로 테스트 (DOM을 조회하고 사용자와 비슷한 방식으로 이벤트를 발생시킴)
단위 테스트 대상 선정하기
모킹
import { screen } from '@testing-library/react';
import React from 'react';
import EmptyNotice from '@/pages/cart/components/EmptyNotice';
import render from '@/utils/test/render';
const navigateFn = vi.fn();
vi.mock('react-router-dom', async () => {
const original = await vi.importActual('react-router-dom');
// 실제 모듈을 모킹하여 useNavigate 훅을 spy 함수로 대체하여 반환
return { ...original, useNavigate: () => navigateFn };
});
it('"홈으로 가기" 링크를 클릭할경우 "/"경로로 navigate함수가 호출된다', async () => {
const { user } = await render(<EmptyNotice />);
await user.click(screen.getByText('홈으로 가기'));
expect(navigateFn).toHaveBeenNthCalledWith(1, '/');
});
리액트 훅 테스트 (act 함수)
리액트 훅
act
rerender
import { renderHook, act } from '@testing-library/react';
import useConfirmModal from './useConfirmModal';
it('호출 시 initialValue 인자를 지정하지 않는 경우 isModalOpened 상태가 false로 설정된다.', () => {
// result: 훅을 호출하여 얻은 결과 값을 반환 -> result.current 값의 참조를 통해 최신 상태를 추적할 수 있다.
// rerender: 훅을 원하는 인자와 함께 새로 호출하여 상태를 갱신한다. (주로 props의 값이 변경되어 전달하는지 확인하는 용도)
const { result } = renderHook(useConfirmModal);
expect(result.current.isModalOpened).toBe(false);
});
it('호출 시 initialValue 인자를 boolean 값으로 지정하는 경우 해당 값으로 isModalOpened 상태가 설정된다.', () => {
const { result } = renderHook(() => useConfirmModal(true));
expect(result.current.isModalOpened).toBe(true);
});
it('훅의 toggleIsModalOpened()를 호출하면 isModalOpened 상태가 toggle된다.', () => {
const { result, rerender } = renderHook(useConfirmModal);
// act : 상호작용 (렌더링,이펙트 등..)을 함게 그룹화하고 실행하여 실제 앱에서 동작하는 것처럼 렌더링과 업데이트를 상태 반영하도록 도와줌.
// 업데이트 내용을 jsdom에 반영할 때 사용함.
act(() => {
result.current.toggleIsModalOpened();
});
expect(result.current.isModalOpened).toBe(true);
});
타이머 테스트
userEvent vs fireEvent
fireEvent
userEvent
테스트 코드 작성 시에는 userEvent를 활용해 실제 상황과 유사하도록 테스트의 신뢰성을 높히고,
지원하지 않는 부분이 있을 때, fireEvent 활용 (ex: scroll )
단위 테스트의 한계
공용 컴포넌트, 커스텀 훅, 공통 유틸처럼 다른 모듈에 대한 의존성이 거의 없을 때,
해당 모듈 자체만으로 독립적인 역할을 할 때 테스트를 진행하기 때문에 여러 모듈이 조합 되었을때
발생하는 이슈를 찾을수 없다. 또한 비즈니스 요구사항에 맞게 동작하는지 보장 할 수 없기때문에
통합 테스트, E2E 테스트등 다양한 테스트로 보강하여야 한다.