jest.mock은 JavaScript 테스트 프레임워크인 Jest에서 특정 모듈이나 함수의 동작을 가짜(mock)로 바꾸기 위해 사용된다. jest.mock을 활용하면 외부 의존성(데이터베이스, API 호출, 파일 시스템 등) 없이 단위 테스트를 수행할 수 있어 테스트 속도가 빨라지고, 테스트 환경을 보다 안정적으로 만들 수 있다.
# 기본 사용법
jest.mock(moduleName, factory) 메서드는 두 가지 매개변수를 받는다:
- moduleName: 모의(mock)하려는 모듈의 경로 또는 이름.
- factory: 선택 사항으로, 가짜(mock) 구현을 반환하는 함수.
jest.mock('module-name');
예시는 'module-name' 모듈을 모의(mock)로 전환한다. 이 경우 기본적으로 자동 모의(자동으로 생성된 가짜 함수)가 제공된다.
# 모의 함수의 기본 동작
모듈을 jest.mock()으로 모의하게 되면:
- 해당 모듈의 모든 함수는 자동으로 모의 함수(mock function)가 된다.
- 모의 함수는 기본적으로 undefined를 반환하며, 호출 여부를 추적할 수 있다.
- 필요에 따라 모의 함수의 반환값이나 동작을 설정할 수 있다.
# 자동 모의 vs 수동 모의
1) 자동 모의(Auto Mocking)
jest.mock('module-name')을 사용하면, Jest는 해당 모듈의 모든 함수를 자동으로 모의(mock)한다. 자동 모의는 해당 함수들이 단순한 jest.fn()으로 대체된다.
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// math.test.js
import * as math from './math';
jest.mock('./math');
test('add function is mocked', () => {
math.add.mockReturnValue(3); // mock에서 반환값을 정의
expect(math.add(1, 2)).toBe(3); // 실제 동작과 관계 없이 3을 반환
});
예시에서 math.add는 더 이상 실제로 작동하지 않고 모의 함수로 대체된다.
2) 수동 모의(Manual Mocking)
Jest는 수동으로도 모듈을 모의(mock)할 수 있다. 이를 위해 factory 함수를 두 번째 인자로 전달하여 직접 가짜 구현을 정의할 수 있다.
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// math.test.js
import * as math from './math';
jest.mock('./math', () => ({
add: jest.fn(() => 10), // add 함수는 언제나 10을 반환
subtract: jest.fn(() => 5), // subtract 함수는 언제나 5를 반환
}));
test('add function returns 10', () => {
expect(math.add(1, 2)).toBe(10);
});
test('subtract function returns 5', () => {
expect(math.subtract(10, 5)).toBe(5);
});
이 방식에서는 각 함수의 동작을 세밀하게 정의할 수 있으며, 모듈 내부의 특정 함수들만 모의할 수 있다.
# 모의 함수의 동작 설정
모의 함수는 다양한 방식으로 동작을 설정할 수 있다. 대표적인 방법은 다음과 같다:
1) mockReturnValue
모의 함수가 항상 특정 값을 반환하도록 설정한다.
const myMock = jest.fn();
myMock.mockReturnValue('default value');
console.log(myMock()); // 'default value'
2) mockResolvedValue
비동기 함수에서 Promise.resolve와 같이 동작하도록 설정한다. 즉, 모의 함수가 항상 특정 값을 포함한 Promise를 반환하게 한다.
const myMock = jest.fn();
myMock.mockResolvedValue('resolved value');
myMock().then((value) => console.log(value)); // 'resolved value'
3) mockRejectedValue
비동기 함수에서 Promise.reject와 같이 특정 에러를 포함한 Promise를 반환하게 한다.
const myMock = jest.fn();
myMock.mockRejectedValue(new Error('error'));
myMock().catch((e) => console.log(e.message)); // 'error'
4) mockImplementation
모의 함수의 전체 동작을 재정의할 수 있다. 이 방식은 복잡한 로직을 구현할 때 유용하다.
const myMock = jest.fn().mockImplementation((a, b) => a + b);
console.log(myMock(1, 2)); // 3
5) mockImplementationOnce
모의 함수의 동작을 한 번만 설정할 수 있다. 그 이후에는 기본 동작으로 돌아간다.
const myMock = jest.fn().mockImplementationOnce(() => 'first call').mockImplementationOnce(() => 'second call');
console.log(myMock()); // 'first call'
console.log(myMock()); // 'second call'
console.log(myMock()); // undefined (이후에는 기본 동작)
# 특정 함수만 모의하기
모듈 내에서 특정 함수만 모의하고 나머지는 실제로 동작하도록 설정하려면 jest.spyOn()을 사용할 수 있다.
// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// math.test.js
import * as math from './math';
test('spyOn add function', () => {
const addSpy = jest.spyOn(math, 'add').mockReturnValue(10);
expect(math.add(1, 2)).toBe(10);
addSpy.mockRestore(); // 원래 함수로 복구
expect(math.add(1, 2)).toBe(3); // 실제 함수가 실행됨
});
jest.spyOn을 사용하면 함수의 일부 호출을 모의(mock)로 대체하고, 이후 다시 원래 동작으로 복구할 수 있다.
# 타이머 및 글로벌 객체 모의
1) 타이머 모의
setTimeout, setInterval과 같은 타이머 함수들도 jest.useFakeTimers()를 사용하여 모의할 수 있다.
jest.useFakeTimers();
test('calls setTimeout with 1000ms', () => {
const callback = jest.fn();
setTimeout(callback, 1000);
jest.runAllTimers(); // 모든 타이머 즉시 실행
expect(callback).toBeCalled();
});
2) 글로벌 객체 모의
window.fetch 같은 글로벌 객체도 모의할 수 있다.
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ data: 'test data' }),
})
);
# 모의 리셋 및 초기화
모의 함수의 상태를 리셋하거나 초기화할 수 있다:
- mockClear(): 함수 호출 기록을 초기화한다.
- mockReset(): 호출 기록과 함께 모의 함수 구현 자체를 리셋한다.
- mockRestore(): 원래 함수 구현을 복구한다(스파이 함수 사용 시 유용).
const myMock = jest.fn().mockReturnValue('test');
myMock();
expect(myMock).toHaveBeenCalled();
myMock.mockClear();
expect(myMock).not.toHaveBeenCalled();
# 모의 함수 호출 추적
모의 함수가 어떻게 호출되었는지, 몇 번 호출되었는지, 어떤 인자들로 호출되었는지를 추적할 수 있다.
const myMock = jest.fn();
myMock(1);
myMock(2, 'second call');
expect(myMock).toHaveBeenCalledTimes(2); // 2번 호출됨
expect(myMock).toHaveBeenCalledWith(1); // 첫 번째 호출에서 1로 호출됨
expect(myMock).toHaveBeenLastCalledWith(2, 'second call'); // 마지막 호출에서 2와 'second call'로 호출됨
결론
jest.mock은 테스트 환경에서 모듈과 함수의 동작을 모의하기 위한 강력한 도구이다. 이를 통해 외부 의존성을 제거하고, 테스트 환경을 제어할 수 있으며, 가짜 데이터를 기반으로 다양한 테스트 시나리오를 설정할 수 있다.