與時間有關的測試
有時候需要確認代碼在特定日期仍正確執行,或是根據時間顯示正確的資料,就會需要能夠操縱時間。
Rails 內建 ActiveSupport::Testing::TimeHelpers
:http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html
Ruby 專案則可以使用 Timecop 這個專案:https://github.com/travisjeffery/timecop。
ActiveSupport::Testing::TimeHelpers
主要提供了三個方法:
travel_to(date_or_time) { ... }
移動到特定的時間點。
travel(duration, &block)
移動一段時間。
travel_back()
從特定時間點回到當下。
配置
spec/spec_helper.rb
加入:
RSpec.configure do |config|
config.include ActiveSupport::Testing::TimeHelpers
end
在測試裡便可以使用上面提到的三個方法。
例子
移動到特定時間點檢查 View 的內容,比如:
# app/views/layouts/application.html.erb
...
<footer>
<p>© <%= Time.current.year %> 深圳新生教育科技有限公司</p>
</footer>
在頁面上顯示:
© 2016 深圳新生教育科技有限公司
可以寫 Controller 測試來檢查
RSpec.describe ApplicationController do
describe "#index" do
def do_request
get :index
end
it "should be success" do
do_request
expect(response).to be_success
end
context "from the future" do
render_views
it "display year correctly" do
travel_to Time.new(2046, 1, 1, 0, 0, 0) do
do_request
expect(response.body).to match /© 2046 深圳新生教育科技有限公司/
end
end
end
end
end
render_view 是 RSpec::Rails
提供的方法,預設 Controller spec 不會 render view,這裡我們要檢查 view 的內容所以要 render。
travel_to Time.new(2046, 1, 1, 0, 0, 0) do
# 這裡面時間是 2046 年
end
view rendered 的內容可以在 response.body
拿到。
例子
比如 Coupon 在七天後過期。
class Coupon
def valid?
(Time.current - created_at) < 7.days
end
end
RSpec.describe Coupon do
describe "#valid?" do
context "within a week" do
it "returns true" do
coupon = Coupon.new
expect(coupon.valid?).to be true
end
end
context "after a week" do
it "returns false" do
coupon = Coupon.new
travel 8.days do
expect(coupon.valid?).to be false
end
travel_back # 記得測試跑完要把時間還原
end
end
end
end
travel_to
接受特定日期,而 travel
則是接受一段時間。
看怎麼樣搭配使用可以提高測試的可讀性,但使用 travel
要記得使用 travel_back
,不然其他測試的時間就亂了。
例子 3
特賣會標題!
class Sale
# Sale on 2016/10/12
def title
"Sale on #{Time.current.strftime('%Y/%m/%d')}"
end
end
RSpec.describe Sale do
describe "#title" do
it "shows correct date in title" do
travel_to Time.zone.local(2046, 1, 15, 0, 0, 0) do
result = Sale.new.title
expect(result).to eq "Sale on 2046/1/15"
end
end
end
end
學會了 ActiveSupport::Testing::TimeHelpers
怎麼用以後,Timecop 依樣畫葫蘆請參考 README:https://github.com/travisjeffery/timecop。