Reputation: 2217
So I have an application that revolves around events on a calendar. Events have a starts_at and ends_at. A new requirement has been added to restrict the creation of new events to only be in the future, more specifically >= midnight today. So naturally, I modified my validate method to check for this at instantiation. This however creates a problem when testing with RSpec using FactoryGirl.
A lot of tests require checking certain requirements with events in the past. Problem is, I can no longer create those elements in the past since it fails my validation. So I've found a few ways to get around this with
allow(instance)to receive(:starts_at).and_return(some_future_time)
or
expect_any_instance_of(Event).to receive(:check_valid_times).and_return(true)
Here's some simple code from the app
#Model
class Event < ActiveRecord::Base
validate :check_for_valid_times
private:
def check_for_valid_times
if starts_at.present? && (starts_at < Time.now.at_beginning_of_day)
errors.add(:base, I18n.t('event.start_time_before_now'))
end
unless starts_at.present? && (starts_at < ends_at)
errors.add(:base, I18n.t('event.end_time_before_start'))'
end
end
end
My factory
#factory
require 'factory_girl'
FactoryGirl.define do
factory :event do
starts_at { 2.hour.from_now.to_s }
end
end
The question: Is there a nice clean way to do this instead of having to go handle each creation of an event and dealing with them specifically in all my tests? Currently I've having to go deal with quite a few of them in varying ways.
Let me know if there are other parts of the code I should be posting up.
As always, Thanks in advance for your help!
Upvotes: 1
Views: 214
Reputation: 6808
The way I generally solve problems like this is the timecop
gem.
For instance:
Timecop.freeze 1.hour.ago do
create(:event)
end
You can then place these in let
blocks, or in a helper in your spec/support/events.rb
to keep it DRY and maintainable.
Using timecop, you can actually simulate a test completely. So create the event correctly at the time in the past that you care about, then return time to normal and see that your tests show that the event is in the past and cant be altered, and so on. It allows complete, accurate and understandable time-sensitive tests. RSpec helpers, shared contexts and before/let blocks can handle keeping the tests clean.
Upvotes: 2