TimerMock
setTimeOut()
, setInterval()
, clearTimeout()
, clearInterval()
는 실제 시간이 경과해야 하기 떄문에 테스트 환경에 적합하지 않다.
jest는 타이머를 제어할 수 있는 함수로 대체하여 시간을 제어한다.
가짜 타이머 활성화
jest.useFakeTimers()
를 호출하여 가짜 타이머를 활성화할 수 있다.타이머는
jest.useRealTimers()
로 원래 동작으로 복원할 수 있다.
function timerGame(callback) {
console.log("Ready....go!");
setTimeout(() => {
console.log("Time's up -- stop!");
callback && callback();
}, 1000);
}
module.exports = timerGame;
jest.useFakeTimers();
jest.spyOn(global, "setTimeout");
test("게임이 끝나기 전에 1초를 기다립니다.", () => {
const timerGame = require("../timerGame");
timerGame();
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
});
모든 타이머 실행
Jest 타이머 제어 API를 사용하여 테스트 중에 시간을 빠르게 진행할 수 있다.
jest.useFakeTimers();
test("1초 후 콜백을 호출합니다.", () => {
const timerGame = require("../timerGame");
const callback = jest.fn();
timerGame(callback);
// 이 시점에서는 콜백이 아직 호출되지 않았어야 합니다.
expect(callback).not.toHaveBeenCalled();
// 모든 타이머가 실행될 때까지 빠르게 진행합니다.
jest.runAllTimers();
// 이제 콜백이 호출되었어야 합니다!
expect(callback).toHaveBeenCalled();
expect(callback).toHaveBeenCalledTimes(1);
});
대기 중인 타이머 실행
재귀 타이머와 같은 시나리오에서 타이머가 자신의 콜백에서 새로운 타이머를 설정한다.
이런 경우
runAllTimers()
을 사용하면 무한 루프에 빠져 오류가 발생한다.이 경우
jest.runOnlyPendingTimers()
를 사용하여 문제를 해결할 수 있다.
function infiniteTimerGame(callback) {
console.log("Ready....go!");
setTimeout(() => {
console.log("Time's up! 10초 후 다음 게임이 시작됩니다...");
callback && callback();
// 10초 후에 다음 게임을 예약합니다.
setTimeout(() => {
infiniteTimerGame(callback);
}, 10000);
}, 1000);
}
module.exports = infiniteTimerGame;
jest.useFakeTimers();
jest.spyOn(global, "setTimeout");
describe("infiniteTimerGame", () => {
test("1초 후 10초 타이머를 예약합니다.", () => {
const infiniteTimerGame = require("../infiniteTimerGame");
const callback = jest.fn();
infiniteTimerGame(callback);
// 이 시점에서는 1초 후에 게임이 종료되도록 setTimeout이 한 번 호출되었어야 합니다.
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
// 현재 대기 중인 타이머만 빠르게 진행합니다.
// (해당 과정에서 생성된 새로운 타이머는 포함되지 않습니다.)
jest.runOnlyPendingTimers();
// 이 시점에서는 1초 타이머의 콜백이 실행되었어야 합니다.
expect(callback).toHaveBeenCalled();
// 그리고 10초 후에 게임을 다시 시작하도록 새로운 타이머가 생성되었어야 합니다.
expect(setTimeout).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 10000);
});
});
타이머를 시간 단위로 진행
jest.advenceTimersByTime(msToRun)
을 사용하면 API가 호출되면 모든 타이머가msToRun
밀리초만큼 진행된다.테스트 에서 대기 중인 모든 타이머를 지워야 하는 상황에는
jest.clearAllTimers()
를 사용할 수 있다.
function timerGame(callback) {
console.log("Ready....go!");
setTimeout(() => {
console.log("Time's up -- stop!");
callback && callback();
}, 1000);
}
module.exports = timerGame;
jest.useFakeTimers();
it("1초 후 콜백을 호출합니다 (advanceTimersByTime 사용)", () => {
const timerGame = require("../timerGame");
const callback = jest.fn();
timerGame(callback);
// 이 시점에서는 콜백이 아직 호출되지 않았어야 합니다.
expect(callback).not.toHaveBeenCalled();
// 모든 타이머가 실행될 때까지 빠르게 진행합니다.
jest.advanceTimersByTime(1000);
// 이제 콜백이 호출되었어야 합니다!
expect(callback).toHaveBeenCalled();
expect(callback).toHaveBeenCalledTimes(1);
});
Last updated