在Ruby on Rails測試環境凍結當下時間
試想以下情境,今天我們做出了一個功能:
在後台設定遊戲的維修時間,前台的遊戲就會依設定的時間自動切換狀態 。
若我們想自己寫一個測試程式來測試一下功能是不是正常,基本的做法可能就是先在測試環境設一個假的維修時間,然後抓取當下的時間來判定遊戲要不要切維修狀態,但這樣過了我們造假的維修時間後,就再也測不到前台頁面有沒有依維修時間切狀態了,因爲當下的時間是一直改變了。
所以若想讓測試程式是可以一直測試到依維修時間切換狀態的功能,如果可以,應該會想把時間凍結在維修時間範圍內。
希望將當下的時間凍結住:
如果我們可以把時間凍結在維修時間範圍內,這樣每次跑測試程式的時候,就可以一直測試這個功能了。
如何把時間凍住呢,首先,我們可能會先聯想到Time.now或是Time.current這兩個方法,這兩個方法基本上都是用來得到當下時間的方法,在Ruby的世界裡,Time是一個類別物件,他本身具備了許多方法,now跟current就是其中的內建類別方法,讓我們忽見的時候就可以得到當下的時間,所以想要把時間凍住的話,可以從這邊著手,把current或now方法原本是抓當下時間覆蓋成我們想要的時間就可以了。
可採用方法:
1. Rspec提供基本的凍結Time.current方法
current = Time.parse('2019-02-18 11:24:59')
allow(Time).to receive(:current) { current }
所以我們只要在我們做測試的每一個example都先執行上面這兩行程式碼,這樣在我們的測試環境中,Time.current都會是我們設定的時間日期了!
RSpec.describe ChangeCompanyGamesStatusService do.........describe 'during maintenance time, change status' do
before {
current = Time.parse('2019-02-18 11:24:59')
allow(Time).to receive(:current) { current }
}it 'is_maintenance is true' do.........end
2. 使用gem — time-warp
其他還有像time-warp這個gem,也提供了方法,讓我們在測試的時候,呼叫pretend_now_is這個方法來凍結著當下時間
pretend_now_is(2000,"jan",1,0) do
Time.now
end
3. 寫一個Time類別物件並在裡面寫一個currrent 的類別方法
我們也可以直接在測試程式中,直接寫一個Time的類別物件,然後將原本的current方法蓋掉
before {
class Time
def self.current
'2019-02-18 11:24:59'
end
end
}
結論
要採用哪一種方法,主要端看我們想要凍結時間的需求是什麼,基本上,採用內建的方法都很便利,但如果有比較特殊的需求,當然還是自行寫一個類別物件然後撰寫方法最便利。