I want to test a method that follows one path if the current date is between Jan 1st - Aug 1st, or it follows another path if the current date is between Aug 2nd - December 31st. example:
def return_something_based_on_current_date
if date_between_jan_1_and_aug_1?
return "foo"
else
return "bar"
end
end
private
def date_between_jan_1_and_aug_1?
date_range = build_date_range_jan_1_through_aug_1
date_range === Date.today
end
def build_date_range_jan_1_through_aug_1
Date.today.beginning_of_year..Date.new(Date.today.year, 8, 1)
end
As you can see: return_something_based_on_current_date
depends heavily upon Date.today
, as does the private methods it invokes. This is making it difficult to test both paths within this method since Date.today
dynamically returns the current date.
For testing purposes: I need Date.today
to return a static date that I want it to so that I can test that each path is working correctly.
Question : Is there a way that I can make Date.today
return a value that I make up within my spec? After the specs that test the return_something_based_on_current_date
: I want the dynamic implementation of Date.today
to go back to its usual implementation. I just need control over Date.today
to test this method.
Add this to your before block
.
allow(Date).to receive(:today).and_return Date.new(2001,2,3)
I *think* it is not necessary to unstub.
I recommend you look at the Timecop gem, it allows to freeze the time at a given date.
On top of stubbing the current Time, it also allows to travel in time for a given test
https://github.com/travisjeffery/timecop
describe "some set of tests to mock" do
before do
Timecop.freeze(Time.local(1990))
end
after do
Timecop.return
end
it "should do blah blah blah" do
end
end
Update
As Andy mentions in the comments, there is a helper method travel_to
available since Rails 4.1
Reference is available here: http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html
There's another approach you might want to consider, that doesn't require any stubbing – change the public method to accept an argument for the current date.
Clarification:
Change def return_something_based_on_current_date
to def return_something_based_on_current_date(current_date)
, then change all instances of Date.today
to current_date
. You'll also need to pass current_date
into the private methods.
Then in your tests, you can pass whatever you want as current_date
.
I was in a similar situation but I didn't want to install the gem. as I was interested in time intervals bigger than one day so I decided to do it this way
it 'Creates an event for tomorrow' do
event = FactoryBot.create(:event, :tomorrow)
expect(event.date.day).to eq (Time.now + 1.day).day
end
it 'Creates an event for the next week' do
event = FactoryBot.create(:event, :next_week)
expect(event.date.day).to eq (Time.now + 1.week).day
end
it 'Creates an event for the next month' do
event = FactoryBot.create(:event, :next_month)
expect(event.date.day).to eq (Time.now + 1.month).day
end
so I just tested the expected date, I am afraid that there is a specific time of the day that the test will be broken but I don't care
Since Rails 4.2 there's the ActiveSupport::Testing::TimeHelpers
module that provides a straightforward way to do this:
travel_to(Time.parse("2019-01-19")) do
# your code here
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.