見出し画像

【Jest_48】 jest.useFakeTimers() の使い方は?

Jestのjest.useFakeTimers()【使い方&活用法】


1. そもそもjest.useFakeTimers()とは?

  • Jestが提供するタイマー関数(setTimeout, setInterval, clearTimeout, clearInterval)のモック機能

  • 本物のタイマーを置き換え、時間を手動で進めることができる

  • テストの高速化・安定化に必須の機能


2. なぜfake timersが必要か?

  • 通常のタイマーを使うと実際に時間を待つためテストが遅くなる

  • テスト実行中の非同期挙動を正確に制御したい

  • タイマーのコールバックがいつ呼ばれるかを明示的に操作したい


3. jest.useFakeTimers() の基本的な使い方

beforeEach(() => {
  jest.useFakeTimers();
});

afterEach(() => {
  jest.useRealTimers();
});

test('setTimeout callback', () => {
  const mockFn = jest.fn();

  setTimeout(mockFn, 1000);

  expect(mockFn).not.toBeCalled();

  jest.advanceTimersByTime(1000);

  expect(mockFn).toBeCalled();
});
  • jest.useFakeTimers() でタイマーをモック化

  • jest.advanceTimersByTime(ms) で擬似的に時間を進める

  • jest.useRealTimers() でモックを解除し、実タイマーに戻す


4. Jestのfake timersの種類(モダンとレガシー)

4-1. レガシー(fake timers)

jest.useFakeTimers('legacy');
  • 従来からのfake timers

  • いくつかのES6機能に非対応で古い挙動がある

4-2. モダン(fake timers)

jest.useFakeTimers('modern');
  • Jest 27以降のデフォルト

  • @sinonjs/fake-timersを使用し、ES6以降のAPIもサポート

  • より正確で堅牢


5. タイマーを進めるメソッドまとめ

jest.advanceTimersByTime(ms)
 指定時間分だけタイマーを進める
jest.runAllTimers()
 保留中の全てのタイマーを即座に実行
jest.runOnlyPendingTimers()
 保留中のタイマーのみ実行
jest.clearAllTimers()
 保留中のタイマーを全てキャンセル


6. 実践的な使い方例

6-1. setTimeoutのテスト

test('delayed call', () => {
  const mockFn = jest.fn();
  setTimeout(mockFn, 2000);

  // 1秒経過、まだ呼ばれていない
  jest.advanceTimersByTime(1000);
  expect(mockFn).not.toBeCalled();

  // さらに1秒経過で呼ばれる
  jest.advanceTimersByTime(1000);
  expect(mockFn).toBeCalledTimes(1);
});

6-2. setIntervalのテスト

test('interval calls', () => {
  const mockFn = jest.fn();
  const id = setInterval(mockFn, 1000);

  jest.advanceTimersByTime(1000);
  expect(mockFn).toHaveBeenCalledTimes(1);

  jest.advanceTimersByTime(3000);
  expect(mockFn).toHaveBeenCalledTimes(4);

  clearInterval(id);
});

7. async/awaitと組み合わせた使い方

test('async with timers', async () => {
  const mockFn = jest.fn();

  setTimeout(mockFn, 1000);

  jest.advanceTimersByTime(1000);

  // 次のTickまで待つ
  await Promise.resolve();

  expect(mockFn).toBeCalled();
});

8. タイマーのモック解除と再設定

  • テスト間の影響を防ぐためにbeforeEach/afterEachで使い分けるのが推奨

beforeEach(() => jest.useFakeTimers());
afterEach(() => jest.useRealTimers());

9. 注意点・よくあるトラブル

タイマーが動かずテストが失敗する
 jest.advanceTimersByTime()やjest.runAllTimers()を呼んでいない
async処理のPromiseが解決されない
 await Promise.resolve()で次Tickを待つ
BabelやTransformでタイマー関数が変わる
 環境によってはjest.useFakeTimers('modern')を明示的に指定
モックタイマー解除忘れ
 テスト間で副作用が出るため、afterEachでjest.useRealTimers()を呼ぶ


10. まとめ

jest.useFakeTimers()
 タイマー関数をモック化し、時間制御可能にする
モダンモードがおすすめ
 Jest 27以降は'modern'モードでより正確に動作
時間を進めるコマンド
 advanceTimersByTimeやrunAllTimersなど多彩な操作
asyncテストとの相性
 Promiseの解決タイミングにも注意しつつ使う
モック解除は必須
 テストの独立性を保つためにuseRealTimers()で戻す



いいなと思ったら応援しよう!