sinon.jsのuseFakeTimersを使った時間制御とvowsを使う際の書き方
nodeで時間依存なテストコードを書きたい場合、偽のタイマーを使って時間制御する
サンプル読んで本当にそんなことができんのかい、と疑問だったので、最小コードだけで挙動だけ確認したメモ
いれる
npm install sinon
偽のタイマーを使う
>sinon = require("sinon") >clock = sinon.useFakeTimers()
ここで注意するべきなのは sinon#useFakeTimers()した時点でDateクラスは上書きされ、unixtimeで起点となるGMT 1970年1月1日にリセットされる。明示的にclock#tickを呼び出さない限り、この時間は動かない。
>now = new Date() Thu, 01 Jan 1970 00:00:00 GMT
時間を進める
clock#tickで60秒進めてみる。
> clock.tick(1000*60) > new Date() Thu, 01 Jan 1970 00:01:00 GMT
午前0時1分にまで進んだ。
元に戻す
clock#restoreを呼ぶ
>clock.restore() >new Date Sun, 15 Jan 2012 20:12:16 GMT
無事現在の時刻に戻った。
VowsでuseFakeTimersを使う際の注意
Vowsで同じバッチの中の処理は並列実行されてしまう。
Dateオブジェクトというグローバルなオブジェクトをいじってる以上、ちゃんとrestoreしてから次のテストにうつらないと失敗する。
teardownでちゃんと後処理をしましょう。
以下CoffeeScript
単体で実行してる場合(大丈夫な例)
sinon = require 'sinon' vows.describe('時間経過のテスト').addBatch '30分経過させる': topic : -> @clock = sinon.useFakeTimers() return new Date "経過させた時間は元の時間と異なる":(topic)-> @clock.tick 30*60*1000 assert.notEqual topic , new Date teardown:-> @clock.restore()
だめな例
sinon = require 'sinon' vows.describe('時間経過のテスト').addBatch '1秒経過させる': topic : -> @clock = sinon.useFakeTimers() new Date "時間経過を確認":(topic)-> @clock.tick 1000 assert.equal (new Date).getTime-topic.getTime() , 1000 teardown:-> @clock.restore() '1秒経過させる(並列に実行される)': topic : -> @clock = sinon.useFakeTimers() new Date "時間経過を確認":(topic)-> @clock.tick 1000 assert.equal (new Date).getTime-topic.getTime() , 1000 teardown:-> @clock.restore()
逐次実行するように分割
vows.describe('時間経過のテスト') .addBatch '1秒経過させる': topic : -> @clock = sinon.useFakeTimers() new Date "時間経過を確認":(topic)-> @clock.tick 1000 assert.equal (new Date).getTime-topic.getTime() , 1000 teardown:-> @clock.restore() .addBatch '1秒経過させる(逐次)': topic : -> @clock = sinon.useFakeTimers() new Date "時間経過を確認":(topic)-> @clock.tick 1000 assert.equal (new Date).getTime-topic.getTime() , 1000 teardown:-> @clock.restore()