In rspec 3.1.0, a spec can use #allow to stub a method:
describe do
specify do
o = Object.new
allow(o).to receive(:foo)
o.foo
end
end
This works fine. However, if the stub is within a method in a class, then the #allow method is not defined:
describe do
class Baz
def allow_bar(o)
allow(o).to receive(:bar)
end
end
specify do
o = Object.new
Baz.new.allow_bar(o)
o.bar
end
end
The error is:
Failure/Error: allow(o).to receive(:bar)
NoMethodError:
undefined method `allow' for #<Baz:0x8de6720>
# ./bar_spec.rb:5:in `allow_bar'
# ./bar_spec.rb:11:in `block (2 levels) in <top (required)>'
The test defines its test double as a regular class rather than using rspec's "double" method. This is because the test double has a thread. Inside the test double is this code:
if command == :close
# Note: Uses the old (rspec 2) syntax. Needs to be converted
# to rspec 3 syntax using the #allow method.
socket.stub(:getpeername).and_raise(RuntimeError, "Socket closed")
end
This prevents the code under test from erroneously using the socket after the session has been closed.
I can give the test double access to #allow by calling a private API in rspec-mock:
class Baz
RSpec::Mocks::Syntax.enable_expect self # Uses private API
def allow_bar(o)
allow(o).to receive(:bar)
end
end
This works. However, it is explicitly marked as a private API in rspec/mocks/syntax.rb:
# @api private
# Enables the expect syntax (`expect(dbl).to receive`, `allow(dbl).to receive`, etc).
def self.enable_expect(syntax_host = ::RSpec::Mocks::ExampleMethods)
...
In Rspec 3.1, is there a public API I can use to make the expect syntax available within a class?
You can accomplish this by mixing in a few RSpec modules/classes into your class:
class MyClass
include RSpec::Mocks::ExampleMethods::ExpectHost
include RSpec::Matchers
def some_test
expect(1).to eql(1)
end
end