Điều khiển thời gian với gem timecop
This post hasn't been updated for 6 years
Khi viết unit test với rspec trong ứng dụng ruby on rails đôi khi sẽ gặp phải một số case thao tới với thời gian(Date time) mà ta khó có thể control được nó. Ví dụ như chỉ được tạo bản ghi sau 5 phút kể từ khi có request, nhưng khi viết spec sẽ có thêm một case thời gian là invalid
- thường thi ở case này mọi người sẽ viết fake thời gian là 4,59s. Nếu với điều kiện lý tưởng là thời gian chuẩn(không bị delay một chút nào) thì case invalid
này sẽ pass, nhưng ngược lại không may trong thời gian gửi request đến server bị delay mất 1s thì case này chắc chắn là fail rồi phải ko .
Để giải quyết cho vấn đề trên mình xin giới thiệu đến mọi người gem timecop. Đây là một gem cung cấp 2 phương thức chính đó là time freezing
và time travel
, nó cung cấp các phương pháp thống nhất để mô phỏng thời gian tới các phương thức của hệ thống như Time.now, Date.today, and DateTime.now.
Cài đặt
Trên màn hình terminal ta gõ lệnh gem install timecop
để cài đặt.
Đặc điểm và tính năng
- Đóng băng, giữ thời gian hệ thống ở một thời điểm nhất định.
- Thiết lập thời gian hệ thống ở một thời điểm và cho phép thời gian bắt đầu chạy từ đó.
- (Scale time) Thiết lập bước nhảy thời gian của hệ thống (Time step: Ví dụ như thiết lập mỗi một giây thời gian sẽ thay đổi là 1 tiếng - gấp 3600 lần bình thường)
- Không phụ thuộc, có thể sử dụng và làm việc đều đặn với tất cả dự án Ruby, Ruby on Rails.
- Timecop api cho phép các đối số truyền vào
#freeze
and#travel
với một trong các đối tượng dưới đây.
- Time instance
- DateTime instance
- Date instance
- Đối số riêng lẻ (year, month, day, hour, minute, second)
Cách sử dụng
Bạn có thể giả mạo thời gian cho một thiết lập unit test (rspec) đơn giản như bên dưới đây.
describe "some set of tests to mock" do
before do
Timecop.freeze(Time.local(1990)) # Đóng băng thời gian hiện tại của hệ thống trở về năm 1990
end
after do
Timecop.return # Trả về trạng thái ban đầu (Không sử dụng hay là tắt Timecop)
end
it "should do blah blah blah" do
end
end
Để đặt thời gian cho môi trường thử nghiệm trong ứng dụng rails bạn có thể thiết lập ngay trong file môi trường(config/environments/test.rb). Điều này rất có ích khi bạn muốn môi trường test của bạn luôn luôn chạy từ một thời điểm duy nhất nào đó. Ví dụ bên dưới
config.after_initialize do
# Set Time.now to September 1, 2008 10:05:00 AM (at this instant), but allow it to move forward
t = Time.local(2008, 9, 1, 10, 5, 0)
Timecop.travel(t)
end
Sự khác biệt giữa Timecop.freeze và Timecop.travel
- Time freezing: Đóng băng thời gian hệ thống cố định.
- Time travel: Thiết lập thời gian của hệ thống chạy bắt đầu từ một mốc nào đó. Hãy xem xét đoạn code dưới đây:
new_time = Time.local(2008, 9, 1, 12, 0, 0)
Timecop.freeze(new_time)
sleep(10)
new_time == Time.now # ==> true
Timecop.return
Timecop.travel(new_time)
sleep(10)
new_time == Time.now # ==> false
Timecop.scale
Sử dụng cho các trường hợp là cuộc thử nghiệm của bạn mất quá nhiều thời gian chờ, khoảng từ vài chục phút đến vài chục giờ. Ví dụ như test cho trường hợp tạo hóa đơn sau 1 giờ hay thống kê hóa đơn sau 30 ngày chẳng hạn, khi đó bạn có thể set thời gian thích hợp trong method scale để Timecop có thể chạy đúng thời gian đó ngay trong lần init đầu tiên. Demo bên dưới:
Timecop.scale(3600)
Time.now
# => 2012-09-20 21:23:25 +0700
Time.now
# => 2012-09-20 22:23:59 +0700
Kết luận
Bên trên mình đã giới thiệu về gem Timecop để có chúng ta khi viết unit test với rspec sẽ viết dễ hơn với những bài toán liên quan nhiều đến Datetime mà native Ruby khó có thể viết được. Bài viết có thể khó hiểu do mình diễn tả lại chưa được tốt, hy vọng mọi người thông cảm và góp ý ở bên dưới. Thanks!
All Rights Reserved