Ttil : TimeCopはセーフモードです


我々は簡単に現在の日付をモックキングの手段として時間内のシフトをシミュレートするために横断することができるとして仕事でTimeCopを使用します.それは私たちの製品のいくつかの特に複雑な、時間敏感なコンポーネントをテストするための不可欠なツールです.
CodeBaseを通して少し矛盾しているものは、TimeCopのブロックを使用することの間の人々の好みでした.後者はTimeCopを呼び出すことによって正常に時間を戻すために開発者に依存します.終了したら返します.

ロストインタイム


両方とも#freeze and #travel アプリの理解を台無しにTime.now 任意の時点では、正常に時間を返さない場合は何が起こるか?
これは最近、いくつかのflakeyテストの原因としてポップして、彼らの頭をCIで後退させる.私たちには、時間に敏感である異なる地域のテストがたくさんあります.つは、特に、記録がアクセスされた最後の時間を表すタイムスタンプが更新されていたことをテストしていたフレークとして飛び出していました.タイムスタンプが変更されていなかったので、飛び出していたフレークは断続的に失敗していました、しかし、若干の初期のpokingの後、それは実際の機能性がちょうどそれ以外のところで微笑んでいたようでした.
失敗したアサーションは、非常にイベントが設定されていないのを見ていたということです.DateTimeをすばやく検索するには、以下のような設定をした別の関連テストを見つけました.
context 'context 1' do
  before { Timecop.freeze(some_time) }
  after { Timecop.return }
end


context 'context 2' do
  before { Timecop.freeze(some_time) }
end
それで、我々は凍った時間であったが、凍った時間が漏れていて、他のテストに影響を及ぼすようにそれを正常に戻しないテストスイートで設定されている文脈を持ちました.

セーフモード


念頭に置いて、私は本当にこれは私たちが好きだった別のものになることを望んでいない、“あなたはTimeCopを使用するつもりならいつでも、このgotchaについて知っておく必要があります.”幸いにも、ドキュメントを簡単に見て、ライブラリが持っていることを示したa safe mode feature これはブロック構文の使用を強制します.これを次のヘルパーに追加できます.
Timecop.safe_mode = true
これを追加すると、上記のコンテキストのように設定された場所のテストスイートにいくつかのエラーが発生しました.
Timecop::SafeModeException:
       Safe mode is enabled, only calls passing a block are allowed.
テストが失敗したので、今必要なテストのリストがあり、必要なブロック構文を修正して使用します.基本的なバージョンは次のようになります.
it 'does something time-sensitive' do
  Timecop.freeze(some_time) do
    # Some test setup and assertions
  end
end
あなたのテストの終わりには、時間が戻ってコールする必要はありませんでしたTimecop.return . これは、すべての時間に敏感な1つの領域でテストをたくさん持っている場合、これは少し単調になることができますが、あなたはまだ何かに似て達成することができますcontext 1 上記のセットアップフックを使用する.
context 'context 1' do
  around do |example|
    Timecop.freeze(some_time) { example.run }
  end
end
私は、これがどのように判明したかについて、非常に満足でした、flakeyテストのためのむしろ陰険な原因はアイロンをかけられました、そして、図書館を使う2つの方法の間の一貫性の問題はそれらの1つを使用することを強制されることによって解決されました.