0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

sinonのuseFakeTimersはsetTimeoutと一緒に使用できない

Posted at

Sinon.JSでuseFakeTimersを使って現在時刻を変更して単体テストをしていたとき、setTimeoutがおかしくなったので調べてみました。

公式サイトのドキュメント

sinonのAPIリファレンスに説明がちゃんと書いてありました。
(なのでもうここまででこの記事は99%の内容になります。あとは蛇足です。)

APIリファレンスには以下のように書かれていました。

Causes Sinon to replace the global setTimeout, clearTimeout, setInterval, clearInterval, setImmediate, clearImmediate, process.hrtime, performance.now(when available) and Date with a custom implementation which is bound to the returned clock object.

StackOverflowでも同じ内容の質問があり、sinonのuseFakeTimersを使っている間はsetTimeoutは使えないよ、と書かれていました。

つまり、sinonでuseFakeTimersを使っている間、setTimeoutやsetInterval等それとDateオブジェクトのカスタム実装のようなJavaScriptで時間の操作が入るような関数は正常に動作しなくなります。

検証

useFakeTimersを使ったときにsetTimeoutがどのような動きになるのかを検証しました。
使ったJavaScriptファイルは以下のリポジトリに格納しているので、自由に利用してください。

nodejs-module-labo/sinon/useFakeTimers-break at main · s1r-J/nodejs-module-labo

まず、下のようにsinonのuseFakeTimersを呼び出し、時刻を好きな時刻にします
単体テストであれば、現在時刻ではなくテストに最適な時刻を指定して利用します。

const sinon = require('sinon');

const now = new Date();
const timeStub = sinon.useFakeTimers(now.getTime());  // ①

console.log(`now: ${now}`);  // ②

setTimeout(() => {  // ③
  console.log(`timeout: ${new Date()}`);  // ④
}, 2000);

console.log('end');  // ⑤

このコードではsetTimeoutを使っている(③)ため、sinon.useFakeTimersによる影響がなければ以下のようなコンソール出力が得られるはずです。
JavaScriptは非同期のため、②の実行後に⑤が実行され、そのおよそ2秒後にsetTimeoutによって④が実行されるはずです。

now: Fri Apr 01 2022 12:00:00 GMT+0900 (Japan Standard Time)
end
timeout: Fri Apr 01 2022 12:00:02 GMT+0900 (Japan Standard Time)

しかし、実際のコンソール出力は以下のように、④が実行されなくなります。
setTimeoutのような時間操作が関わるメソッドはsinon.useFakeTimersを利用している間は利用できなくなります。

now: Fri Apr 01 2022 12:00:00 GMT+0900 (Japan Standard Time)
end

ただし、先述のJavaScriptコードの②と③の間でtimeStub.restore();を実行することでsetTimeoutを正常に動作させることができます。
restoreはsinon.useFakeTimersの利用を終了して、スタブを片付けるメソッドです。

結論

  • sinonのuseFakeTimersを使っている間は、JavaScriptで時間の操作が入るような関数(setTimeoutやsetInterval等、Dateオブジェクトのカスタム実装)は正常に動作しない
  • sinonのuseFakeTimersを使ったあとはきちんとrestoreする
    • restoreしないと他のテストケースでsetTimeoutなどが正しく動作しなくなる
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?