TDD로 React Counter 컴포넌트와 Custom Hook 테스트하기

jsonLee·2023년 8월 11일
0
post-thumbnail

1. 서론

테스트 주도 개발(Test-Driven Development, TDD)은 현대의 소프트웨어 개발 방법론 중 하나로 널리 알려져 있다. 이번 포스팅에서는 React를 사용한 간단한 예제를 통해 TDD의 기본 원리와 실제 적용 방법을 알아보겠다.

2. TDD란?

TDD는 테스트를 먼저 작성하고 이를 통과할 수 있는 코드를 구현하는 방식이다. 기본 원칙은 다음과 같다:

실패하는 테스트 작성: 원하는 기능의 요구 사항을 반영하는 테스트 코드를 먼저 작성한다.
테스트 통과: 테스트를 통과할 수 있는 최소한의 코드를 작성한다.
코드 개선(Refactor): 코드의 품질을 향상시킨다.

3. TDD의 중요성

  1. 코드 품질 향상: 처음부터 테스트를 작성함으로써 코드의 품질을 지속적으로 관리할 수 있다.
  2. 대한 자신감: 기존 코드를 변경할 때 테스트의 지원을 받아 안전하게 진행할 수 있다.
  3. 버그 감소: 초기 개발 단계에서 버그를 찾아낼 수 있어서 문제를 빠르게 해결할 수 있다.

4. 예제 소개: Counter 컴포넌트 및 Custom Hook

우리가 테스트할 예제는 간단한 Counter 컴포넌트와 이를 지원하는 useCounter Custom Hook이다. Counter 컴포넌트는 버튼을 통해 숫자를 증가시키거나 감소시키는 기능을 한다. useCounter는 해당 기능의 로직을 담당한다.

import { useState } from 'react'

type CounterHook = { count: number, decreaseCount: () => void, increaseCount: () => void }

export function useCounter(): CounterHook {
    const [count, setCount] = useState(0)

    const decreaseCount = () => setCount(count - 1)
    const increaseCount = () => setCount(count + 1)

    return { count, decreaseCount, increaseCount }
}


export default function Counter() {
    const { count, decreaseCount, increaseCount } = useCounter()

    return (
        <div>
            <h1 data-testid="count-value">{count}</h1>
            <button data-testid="increase-button" onClick={increaseCount}>+</button>
            <button data-testid="decrease-button" onClick={decreaseCount}>-</button>
        </div>
    )
}

5. 테스트 코드 작성하기

- Counter Custom Hook 테스트

우선, useCounter Custom Hook의 로직을 테스트한다. 여기서는 Hook의 초기 상태와, 특정 함수를 호출했을 때 상태가 제대로 변경되는지를 확인한다.

import { act, render, renderHook } from "@testing-library/react";
import Counter, { useCounter } from "./Counter";
import { GetByTestId } from "./auth/util";

describe("Counter 커스텀훅 테스트", () => {
    let result: { current: ReturnType<typeof useCounter> };

    beforeEach(() => {
        result = renderHook(() => useCounter()).result;
    });

    it('카운트의 초기값이 0인지 확인', () => {
        const countValue = result.current.count;
        expect(countValue).toBe(0);
    });

    it('increaseCount 함수 호출 시 카운트가 1 증가하는지', () => {
        act(() => {
            result.current.increaseCount();
        });
        const countValue = result.current.count;
        expect(countValue).toBe(1);
    });

    it('decreaseCount 함수 호출 시 카운트가 1 감소하는지', () => {
        act(() => {
            result.current.decreaseCount();
        });
        const countValue = result.current.count;
        expect(countValue).toBe(-1);
    });
});

- Counter 컴포넌트 테스트

다음으로, 컴포넌트가 올바르게 렌더링 되는지, 버튼을 클릭했을 때 상태가 변하는지를 테스트한다.

describe("Counter 컴포넌트 테스트", () => {
    let getByTestId: GetByTestId;

    beforeEach(() => {
        const rendered = render(<Counter />);
        getByTestId = rendered.getByTestId;
    });

    it('초기 카운트 값이 0인지 확인', () => {
        const countValue = getByTestId('count-value');
        expect(countValue).toHaveTextContent('0');
    });

    it('증가 버튼 클릭 시 카운트가 1 증가하는지', () => {
        const increaseButton = getByTestId('increase-button');
        act(() => {
            // fireEvent.click(increaseButton);
            increaseButton.click();
        });
        const countValue = getByTestId('count-value');
        expect(countValue).toHaveTextContent('1');
    });

    it('감소 버튼 클릭 시 카운트가 1 감소하는지', () => {
        const decreaseButton = getByTestId('decrease-button');
        act(() => {
            decreaseButton.click();
        });
        const countValue = getByTestId('count-value');
        expect(countValue).toHaveTextContent('-1');
    });
});

REFERENSE

https://jforj.tistory.com/252

profile
풀스택 개발자

2개의 댓글

comment-user-thumbnail
2023년 8월 11일

좋은 글 감사합니다. 자주 방문할게요 :)

1개의 답글