Search code examples
ruby-on-rails-5rspec-rails

rspec expect child to receive method when parent method is called


class Post
  has_many :comments

  after_update :update_comments

  def update_comments(user)
    comments.where(user: user).each do |comment|
      # binding.pry
      comment.do_something
    end
  end
end

class Comment
  belongs_to :post

  def do_something
    'Ok, I will'
    # binding.pry
  end
end

This is my issue:

RSpec.describe Post do
  describe '#update_comments' do
    let(:post) { create :post }
    let(:comment) { create :comment, post: post }

    it 'triggers comment.do_something'
      comment = post.comments.first
      expect(comment).to receive(:do_something)
      post.update(title: 'new title')
    end
  end
end

I get this error:

(#<Comment id: 1, ..., created_at: "2018-06-15 01:31:33", updated_at: "2018-05-16 02:51:39">).api_update(*(any args))
       expected: 1 time with any arguments
       received: 0 times with any arguments

But if I use binding.pry in either (or both) def(s), I get the console, so I know it's actually being called.

I compared my comment variable in RSpec with self in the Comment class and they match. I tried using post.reload and comment.reload in RSpec to make sure the association was solid. Not sure what else I can do.

The fact that it triggers pry inside the method I'm saying should be received is so baffling to me.

What am I missing?


Solution

  • After a lot more digging, the issue is that my comment variable isn't actually exactly the same instance as the variable that RSpec sees in the loop. They differ by the Rails object ID that is assigned on the fly.

    I needed to use a spy or stub the method to avoid this issue.