Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spying on an instance method with Rspec

Tags:

ruby

rspec

I have a class with several methods, e.g.

class MyClass
  def method_a(p)
    method_b if p == 1
  end

  def method_b
    some_more_stuff
  end
end

And I wish to test, using RSpec, that method_a (sometimes) calls method_b.

it 'calls method_b if the passed parameter is 1' do
  instance = spy('MyClass')

  instance.method_a(1)

  expect(instance).to have_received(:method_b)
end

Unfortunately, because RSpec spies don't pass on method calls to the thing they're spying on, spy.method_a does not in fact call spy.method_b. I've tried playing around with doubles and instance doubles, but am now horribly confused.

How can I have an RSpec double or spy or other instance object observe an instance's internal method calls without completely replacing them? I'm open to mocking out method_b in some manner, but can't figure out how to do that properly either.

like image 678
Brian Carmicle Avatar asked Feb 20 '26 14:02

Brian Carmicle


1 Answers

Generally I don't recommend testing things like this way, since method call is a completely internal thing. Remember, RSpec is BDD framework, and BDD is not about internal things.

However, I understand sometimes we want to test internal things using mocks and stubs. So, here's an example code:

RSpec.describe MyClass do
  it 'calls method_b if the passed parameter is 1' do
    instance = MyClass.new
    expect(instance).to receive(:method_a).and_call_original
    expect(instance).to receive(:method_b)

    instance.method_a(1)
  end
end

The key part is that we actually instantiate MyClass so that we can use and_call_original method only available on partial test doubles.

like image 69
Masafumi Okura Avatar answered Feb 23 '26 10:02

Masafumi Okura



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!