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은 테스트 환경에서 모듈과 함수의 동작을 모의하기 위한 강력한 도구이다. 이를 통해 외부 의존성을 제거하고, 테스트 환경을 제어할 수 있으며, 가짜 데이터를 기반으로 다양한 테스트 시나리오를 설정할 수 있다.

'JavaScript > JavaScript' 카테고리의 다른 글

Await 정리  (1) 2024.09.05

+ Recent posts