Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec/Rails: how to verify that no method of a class is called

I'd like to write something like this:

it 'does not invoke any MyService' do
    MyService.should_not_receive(<any method>)
    tested_method
end

I do not want to list all methods of MyService explicitly because this would lead to a brittle test that could give false positives silently if new methods were added to MyService.

like image 223
Bogatyr Avatar asked Jun 25 '13 06:06

Bogatyr


3 Answers

How about replacing the implementation with a double?

it 'does not invoke any MyService' do
  original_my_service = MyService

  begin
    # Replace MyService with a double.
    MyService = double "should not receive any message"

    tested_method
  ensure
    # Restore MyService to original implementation.
    MyService = original_my_service
  end
end

If methods in MyService are called, it should raise:

RSpec::Mocks::MockExpectationError: Double "should not receive any message" received unexpected message :some_method with (no args)
like image 175
Hari Gopal Avatar answered Oct 17 '22 05:10

Hari Gopal


If you inject the MyService dependency inside your object, you can substitute it with a mock with no methods defined on it, so that any method call will raise an exception.

Let me show you an example:

class Manager
  attr_reader :service

  def initialize(service = MyService)
    @service = service
  end

  def do_stuff
    service.do_stuff
  end

  def tested_method
    other_stuff
  end
end

And the tests would be:

context "#do_stuff" do
  let(:manager) { Manager.new }

  it 'invokes MyService by default' do
    MyService.should_receive(:do_stuff)
    manager.do_stuff
  end
end

context "#tested_method" do
  let(:service) { mock("FakeService") }
  let(:manager) { Manager.new(service) }

  it 'does not invoke any service' do
    expect { manager.tested_method }.not_to raise_error
  end
end
like image 28
Ju Liu Avatar answered Oct 17 '22 05:10

Ju Liu


it 'does not invoke MyService' do
    stub_const('MyService', double)
    tested_method
end

Any attempt to access MyService will return the mocked RSpec double. Since doubles raise errors when they receive messages that aren't explicitly stubbed (and none are being stubbed) any call to MyService will raise an error.

https://relishapp.com/rspec/rspec-mocks/v/3-0/docs/basics/test-doubles

like image 1
DylanReile Avatar answered Oct 17 '22 05:10

DylanReile