Jackson Cunningham
Jackson Cunningham

Reputation: 5073

Rspec testing: NotificationMailer.user_notification(self) returning nil

I'm having trouble with one of my tests

Rspec

  it 'should call send_email_notification on NotificationMailer' do
    expect(NotificationMailer).to receive(:user_notification).with(an_instance_of(User))
    FactoryGirl.create(:user, shop: Shop.new)
  end

Method:

 def send_email_notification
    if user? && self.shop.email_notifications
      NotificationMailer.user_notification(self).deliver_now
    end
  end

undefined method `deliver_now' for nil:NilClass

Which means NotificationMailer.user_notification(self) is returning nil during the tests. But when I run binding.pry in real local environment, NotificationMailer.user_notification(self) returns the proper object. Which means my tests aren't working...

What would you fix?

Upvotes: 2

Views: 419

Answers (1)

sevenseacat
sevenseacat

Reputation: 25029

Using expect.to receive is a mock - basically a stub with an expectation (purists will probably disagree, but whatever). You're stubbing out the method that you've put the expectation on, so it doesn't get called. Typically you would also specify the return value, so the rest of the code you're testing will continue to work with that return value.

You're not specifying the return value here, so the mock is returning nil, making the rest of your code (that depends on the real return value) blow up.

There are two typical courses of action here:

  • Use .and_call_original on the end of your mock - this basically means that the mock won't act like a stub, and it will call the original method with the arguments you passed in. You probably don't want that in this case, because it's a mailer and you don't want to send email in your specs.

  • Specify the return value of the stub, with .and_return. In this case, you might want something like:

    expect(NotificationMailer).to receive(:user_notification).with(an_instance_of(User)).and_return(double(deliver: true))

This will return a test double to your code when you call NotificationMailer.user_notification, that responds to the deliver method and will return true.

More information on test doubles can be found in the RSpec Mocks docs:

https://relishapp.com/rspec/rspec-mocks/docs

Upvotes: 2

Related Questions