Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RSpec Stubbing out Date.today in order to test a method

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.

  • I need to test that the path works correctly if the current date is between Jan 1 - Aug 1
  • I need to test that the path works correctly if the current date is after Aug 1st.

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.

like image 679
Neil Avatar asked Jul 01 '16 18:07

Neil


2 Answers

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.

like image 72
B Seven Avatar answered Oct 05 '22 11:10

B Seven


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

like image 40
Rafal Avatar answered Oct 05 '22 12:10

Rafal