이번에는 React-Testing-Library를 이용해서 Custom Hooks를 테스팅해보겠다. Custom Hooks는 일반적인 함수처럼 테스트 코드를 작성할 수 없다. 그 이유는 Custom Hooks는 React에서 제공하는 Hooks(useState, useEffect...)를 이용한 함수이기 때문이다.
대표적인 Custom Hooks인 useToggle hooks 예시를 보면 다음과 같다.
import { useCallback, useState } from "react";
export default function useToggle(initialState = false) {
const [state, setState] = useState(initialState);
const onToggle = useCallback(() => setState(!state), [state]);
return [state, onToggle, setState] as const;
}
일반적인 함수처럼 테스트코드를 작성할 수 없기 때문에 라이브러리를 추가적으로 설치해줘야 한다.
@testing-library/react-hooks 설치
터미널에 다음 명령어를 입력하여 라이브러리를 설치하자
$ yarn add @testing-library/react-hooks
or
$ npm install @testing-library/react-hooks
useState를 이용한 커스텀 훅 테스트
useState hooks를 이용한 커스텀 훅의 테스트를 하기 위해서 위에서 예시를 들었던 useToggle과 input의 상태를 바꿔주는 useInput hooks를 테스팅해보겠다.
먼저 useToggle을 테스트를 진행해보겠다.
import { useCallback, useState } from "react";
export default function useToggle(initialState = false) {
const [state, setState] = useState(initialState);
const onToggle = useCallback(() => setState(!state), [state]);
return [state, onToggle, setState] as const;
}
테스트 케이스는 다음과 같다.
1) useToggle은 길이가 3인 배열을 리턴한다. [state, onToggle, setState]
2) 매개변수로 initialState 값을 입력하지 않으면 기본 state 값은 false로 설정된다.
3) 매개변수로 initialState 값을 입력하면 state에 그 값이 설정된다.
4) onToggle 함수를 이용해서 state 값을 toggle 할 수 있다.
5) setState 함수를 이용해서 직접 state 값을 변경할 수 있다.
작성한 테스트 코드는 다음과 같다.
import { act, renderHook } from "@testing-library/react-hooks";
import useToggle from "../useToggle";
describe("useToggle", () => {
test("useToggle은 길이가 3인 배열을 리턴한다. (state, onToggle, setState)", () => {
const { result } = renderHook(() => useToggle(false));
expect(result.current).toHaveLength(3);
});
test("매개변수로 initialState 값을 입력하지 않으면 기본 state 값은 false로 설정된다.", () => {
const { result } = renderHook(() => useToggle());
expect(result.current[0]).toBe(false);
});
test("매개변수로 initialState 값을 입력하면 state에 그 값이 설정 된다.", () => {
const { result } = renderHook(() => useToggle(true));
expect(result.current[0]).toBe(true);
});
test("onToggle 함수를 이용해서 state 값을 toggle 시킬 수 있다.", () => {
const { result } = renderHook(() => useToggle(false));
act(() => {
result.current[1]();
});
expect(result.current[0]).toBe(true);
});
test("setState 함수를 이용해서 직접 state 값을 변경할 수 있다.", () => {
const { result } = renderHook(() => useToggle(false));
act(() => {
result.current[2](true);
});
expect(result.current[0]).toBe(true);
});
});
renderHook 함수를 이용해서 우리가 테스트하고자 하는 custom Hooks를 실행시키면, return 값이 result에 담겨 있다. useToggle hooks에서 return 값이 [state, onToggle, setState] 이기 때문에 이 값이 result로 담겨져 있다.
테스트 코드 내부에서 컴포넌트 렌더링 및 상태 변경은 act 함수 내부에서 실행해야 한다
다음은 useInput hooks를 테스팅해보자. useInput의 코드는 아래와 같다.
import React, { useState } from "react";
export default function useInput(initialValue = "") {
const [value, setValue] = useState(initialValue);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
return [value, onChange, setValue] as const;
}
테스트 케이스는 다음과 같다.
1) useInput은 길이가 3인 배열을 리턴한다. [value, onChange, setValue]
2) initialValue를 입력하면 value 값이 설정된다.
3) onChange 함수로 value 값을 변경할 수 있다.
4) setValue 값으로 직접 value를 변경할 수 있다.
작성한 테스트 코드는 다음과 같다.
import { renderHook, act } from "@testing-library/react-hooks";
import useInput from "../useInput";
describe("useInput", () => {
test("useInput은 길이가 3인 배열을 리턴한다. (value, onChange, setValue)", () => {
const { result } = renderHook(() => useInput(""));
expect(result.current).toHaveLength(3);
});
test("initialValue를 입력하면 value 값이 설정 된다.", () => {
const { result } = renderHook(() => useInput("test"));
expect(result.current[0]).toBe("test");
});
test("onChange 함수로 value 값을 변경할 수 있다", () => {
const { result } = renderHook(() => useInput(""));
act(() => {
result.current[1]({
target: { value: "테스트입니다" },
} as React.ChangeEvent<HTMLInputElement>);
});
expect(result.current[0]).toBe("테스트입니다");
});
test("setValue 값으로 직접 value를 변경할 수 있다", () => {
const { result } = renderHook(() => useInput(""));
act(() => {
result.current[2]("두번째 테스트");
});
expect(result.current[0]).toBe("두번째 테스트");
});
});
마치며
이렇게 useState 상태를 이용한 custom hooks의 테스팅을 해봤다. 이 외에도 rerender라는 메서드를 이용한 useEffect 테스트 방식도 있는데 자세한 내용은 https://react-hooks-testing-library.com/ 공식문서를 참고하면 많은 기능을 테스트해볼 수 있다.
'React' 카테고리의 다른 글
Next.js + tanstack-query(react-query)로 server-side-rendering(ssr) 구현하기 (4) | 2023.06.02 |
---|---|
React 18 useDeferredValue와 useTransition 이란? (0) | 2023.05.28 |
React Testing Library(RTL) 사용법 (0) | 2022.03.28 |
[컴포넌트 재활용하기] - Button (2) | 2022.02.19 |
나는 리액트를 어떻게 설계할 것인가? (8) | 2022.02.14 |
댓글