How to use sorbet type checking with RSpec mocks?

Solution 1:

Use instance_double with a proper class and mock it's is_a?. To do that globally perform monkey-patching:

require 'rspec/mocks'

class RSpec::Mocks::InstanceVerifyingDouble
  def is_a?(expected)
    @doubled_module.target <= expected || super
  end
end

Solution 2:

Selectively, do not raise exception when caused by mocks. This way Sorbet still performs types checks unless a mock is used.

require 'sorbet-runtime'

RSpec.configure do |config|
  config.before :each, sorbet: :mocks do
    T::Configuration.inline_type_error_handler = proc do |error|
      raise error unless error.message.include? "got type RSpec::Mocks"
    end

    T::Configuration.call_validation_error_handler = proc do |_signature, opts|
      raise TypeError.new(opts[:pretty_message]) unless opts[:message].include? "got type RSpec::Mocks"
    end
  end


  config.after :each, sorbet: :mocks do
    T::Configuration.inline_type_error_handler = nil
    T::Configuration.call_validation_error_handler = nil
  end
end


Mocha mocks (stub in tests) will not pass any type checks by default. This is deliberate and considered a feature; bare mocks make tests brittle and tend to cause problems when refactoring code, regardless of type checking.

When trying to test a method using a Mocha mock that fails a type check, we recommend rewriting the test to not use Mocha mocks. Either:

  • Create a genuine instance of the object, and use .stubs to replace only certain methods.
  • Write helper functions to create real instances of your objects with fake data.

In the worst case, you can stub is_a? to make a Mocha mock pass a type check, but please avoid doing this. It results in brittle tests and makes code harder to reason about. If you must:

# NOT RECOMMENDED!

fake_llama = stub
fake_llama.stubs(:llama_count).returns(17)
fake_llama.stubs(:is_a?).with(M::Llama).returns(true)

I'm not familiar with the differences between RSpec's mocks and Mocha's mocks (at Stripe where Sorbet is developed we use Mocha) but the principles should be the same.