"jest.fn()" 으로 함수 테스트하기

컴포넌트에는 props 를 사용하여 데이터와 함수를 넘겨주도록 만들 수 있습니다.

이번 포스팅에서는 jest.fn() 을 사용하여 컴포넌트에 넘겨준 함수가 정상동작하는지 테스트하는 방법에 대해 정리합니다.


컴포넌트 props 에 넘겨주는 함수

컴포넌트 props 에는 함수를 넘겨줄 수 있습니다.

사용자 인터렉션을 처리하기 위한 함수가 될 수도 있고, 특정 동작에 대한 callback 으로 활용되도록 구현할 수 있습니다.

이렇게 넘겨준 함수가 의도한 시점, 상황에 호출이 되는지 테스트하고자 합니다.


테스트 예시 컴포넌트

이번 포스팅에서 테스트에 사용할 input 컴포넌트를 만들어보겠습니다.

./ChocobeInput.tsx
import {
    useCallback,
    memo,
    ChangeEvent,
} from 'react';
 
type TChocobeButtonProps = {
    value: string;
    onChange: (value: string) => void;
};
 
function ChocobeInput(props: TChocobeInputProps) {
    const {
        value,
        onChange,
    } = props;
 
    //
    // callback
    //
    const onChangeInput = useCallback((e: ChangeEvent<HTMLInputElement>) => {
        const value = e.target.value;
        onChange(value);
    }, [onChange]);
 
    return (
        <input
            value={value}
            onChange={onChangeInput} />
    );
}
 
export default memo(ChocobeInput);

jest.fn() 으로 onChange mockup function 만들기

Jestfn() 이라는 함수 mockup 메소드 를 제공하고 있습니다.

위 예시 컴포넌트를 테스트한다면, props.onChange() 를 테스트하기 위해 jest.fn() 을 사용하게 됩니다.

jest.fn() 으로 mockup function 생성하기
// UI Components
import ChocobeInput from './ChocobeInput';
// jest
import {
    render,
    screen,
} from '@testing-library/react';
 
describe('ChocobeInput 컴포넌트 테스트', () => {
    it('ChocobeInput 에 값을 입력하면 onChange() 가 호출된다.', async () => {
        const fn_onChange = jest.fn();
 
        render(
            <ChocobeInput
                value=""
                onChange={fn_onChange} />
        );
    });
});

input 요소에 KeyboardEvent 발생시키기

fn_onChange() 함수는 <ChocobeInput /> 컴포넌트에 KeyboardEvent 가 발생하면 호출되는 구조 입니다.

userEvent 를 사용하여 KeyboardEventclick 이벤트 등을 발생시킬 수 있으며, <ChocobeInput /> 컴포넌트의 경우에는 KeyboardEvent 가 발생하면 onChange() 가 호출됩니다.

컴포넌트에 KeyboardEvent 를 발생시키려면 userEvent.type() 메소드를 활용하게 됩니다.

userEvent.type() 으로 KeyboardEvent 발생시키기
// UI Components
import ChocobeInput from './ChocobeInput';
// jest
import {
    render,
    screen,
} from '@testing-library/react';
import {
    userEvent,
} from '@testing-library/user-event';
 
describe('ChocobeInput 컴포넌트 테스트', () => {
    it('ChocobeInput 에 값을 입력하면 onChange() 가 호출된다.', async () => {
        const fn_onChange = jest.fn();
 
        render(
            <ChocobeInput
                value=""
                onChange={fn_onChange} />
        );
 
        const $chocobeInput = screen.getByRole('textbox');
 
        await userEvent.type($chocobeInput, 'Hello');
    });
});

KeyboardEvent 에 의해 fn_onClick() 호출 여부 테스트하기

위 예시 코드를 통해 <ChocobeInput /> 컴포넌트에 KeyboardEvent 가 발생한 상태 입니다.

userEvent.type(요소, 입력값) 으로 넘겨준 입력값 은 문자 1개당 1번의 KeyboardEvent 가 발생하게 되므로, 총 5번의 KeyboardEvent 가 발생한 상태 입니다.

이를 테스트하면 다음과 같습니다.

발생한 이벤트 테스트
// UI Components
import ChocobeInput from './ChocobeInput';
// jest
import {
    render,
    screen,
} from '@testing-library/react';
import {
    userEvent,
} from '@testing-library/user-event';
 
describe('ChocobeInput 컴포넌트 테스트', () => {
    it('ChocobeInput 에 값을 입력하면 onChange() 가 호출된다.', async () => {
        const fn_onChange = jest.fn();
 
        render(
            <ChocobeInput
                value=""
                onChange={fn_onChange} />
        );
 
        const $chocobeInput = screen.getByRole('textbox');
 
        await userEvent.type($chocobeInput, 'Hello');
 
        expect(fn_onChange).toHaveBeenCalledTimes(5);
    });
});

마치며

함수 테스트는 jest.fn() 뿐만 아니라 jest.spyOn() 으로도 가능합니다.

다음 포스팅에서는 jest.spyOn() 으로 테스트하는 방법과 jest.fn() 과 차이점에 대해 정리하겠습니다.