cjn
cjn

Reputation: 1461

Rails RSpec Mocking Date.today.wday in Rake Task

I'm trying to mock Date.today.wday in a rake task in rspec.

Gem versions: RSpec 2.14.8 --- Rails 4.1.1 --- ruby 2.0.0

Here is a simplified fake version of my test to illustrate essentially what I'm trying to do:

describe "scheduler" do
  describe ":thursday_invitations" do
    let(:run_issue_invites) do
      Rake::Task[:thursday_invitations].reenable
      Rake.application.invoke_task :thursday_invitations
    end

    before do
      Rake.application.rake_require 'tasks/scheduler'
      Rake::Task.define_task(:environment)
      Date.today.should_receive(:wday).and_return(4) ###MY NEMESIS CODE LINE
    end

    context "on thursday" do
      it "issues invitations" do
        expect(Date.today.wday).to eq(4) ###THE VERIFICATION TEST THAT KEEPS FAILING
        run_issue_invites
        expect(<other_stuff_to_test>).to <return_properly>
      end
    end
  end
end

So, the real key of this is mocking out the Date.today.wday. Because I want to be able to run my spec on any day of the week, I need to mock/stub out this method to always return "4" (the day-number for Thursday in Rails). So, I initially setup my test to first verify that it is receiving a "4" (the assertion in the test). If today is, say, Friday (which it is) and I run the test, it fails saying that it expected "4" but got "5". That is, it is not returning the value that I want it to when I receive the method. I have tried stubbing with similar ineffective results. Normally, mocking is a breeze, but what seems to be the hangup is .wday which operates on Date.today.

Because this is a rake task (which I'm not as familiar with mocking), I may have to specify something further, but I haven't been able to get to the bottom of it...

Let me know if you need any other clarifying information.

Upvotes: 0

Views: 2115

Answers (1)

rossta
rossta

Reputation: 11494

I believe the reason you're not seeing the behavior you expect is that the object you are mocking is the not the same object under test.

In a Rails 4+ environment, this is what I see on the rails console:

[1]> Date.today.object_id
70104549170200
[2]> Date.today.object_id
70104552970360

The fact that the object_id is different in subsequent calls to Date.today means that each call returns a new object. So Date.today.should_receive(:wday).and_return(4) is setting an expectation on an object that will never be used again.

You'll need to rewrite your spec to ensure the same object is returned by Date.today each time. Here's one solution, omitting other parts of your example for clarity:

let!(:today) { Date.today }

before do
  Date.stub(:today).and_return(today)
  today.should_receive(:wday).and_return(4)
end

it "issues invitations" do
  expect(Date.today.wday).to eq(4)
end

Upvotes: 2

Related Questions