I have a method that uses DateTime.now to perform a search on some data, I want to test the method with various dates but I don't know how to stub DateTime.now nor can I get it working with Timecop ( if it even works like that ).
With time cop I tried
it 'has the correct amount if falls in the previous month' do
t = "25 May".to_datetime
Timecop.travel(t)
puts DateTime.now
expect(@employee.monthly_sales).to eq 150
end
when I run the spec I can see that puts DateTime.now gives 2015-05-25T01:00:00+01:00 but having the same puts DateTime.now within the method I'm testing outputs 2015-07-24T08:57:53+01:00 (todays date).
How can I accomplish this?
------------------update---------------------------------------------------
I was setting up the records (@employee, etc.) in a before(:all) block which seems to have caused the problem. It only works when the setup is done after the Timecop do block. Why is this the case?
TL;DR: The problem was that
DateTime.nowwas called inEmployeebeforeTimecop.freezewas called in the specs.Timecop mocks the constructor of
Time,DateandDateTime. Any instance created betweenfreezeandreturn(or inside afreezeblock) will be mocked.Any instance created before
freezeor afterreturnwon't be affected because Timecop doesn't mess with existing objects.From the README (my emphasis):
So it is essential to call
Timecop.freezebefore you create theTimeobject you want to mock. If youfreezein an RSpecbeforeblock, this will be run beforesubjectis evaluated. However, if you have abeforeblock where you set up your subject (@employeein your case), and have anotherbeforeblock in a nesteddescribe, then your subject is already set up, having calledDateTime.newbefore you froze time.What happens if you add the following to your
EmployeeThen you run the following spec:
Instead of using a
freezeblock, you can alsofreezeandreturnin rspecbeforeandafterhooks:Off-topic, but maybe have a look at http://betterspecs.org/