问题
I'm testing my module and I decided to test it versus anonymous class:
subject(:klass) { Class.new { include MyModule } }
MyModule
uses method name
inside klass
. To let my specs work I need to stub this method name
(which is unimplemented). So I wrote:
subject { klass.new }
allow(subject).to receive(:name).and_return('SOreadytohelp') }
but it raises:
RSpec::Mocks::MockExpectationError: #<#<Class:0x007feb67a17750>:0x007feb67c7adf8> does not implement: name
from spec-support-3.3.0/lib/rspec/support.rb:86:in `block in <module:Support>'
how to stub this method without defining it?
回答1:
RSpec raises this exception because it is not useful to stub a method that does not exist on the original object.
Mocking methods is always error-prone because the mock might behave differently than the original implementation and therefore specs might be successful even if the original implementation would have returned an error (or does not even exist). Allowing to mock non-existing methods is just plain wrong.
Therefore I would argue that you should not try to bypass this exception. Just add a name
method to your class that raises a clear exception if run outside of the test environment:
def self.name
raise NoMethodError # TODO: check specs...
end
回答2:
subject(:klass) do
Struct.new(:name) do
include MyModule
end
end
http://ruby-doc.org/core-2.2.0/Struct.html
回答3:
I think that if the test you're writing is focused on your MyModule
module, and that module relies on an instance method in the class that it is mixed into, then I think that method should be mocked out in the anonymous class that you use when testing the module. For example:
module MyModule
def call_name
# expected implementation of #name to be
# in the class this module is mixed into
name
end
end
RSpec.describe MyModule do
let(:my_module_able) do
Class.new do
include MyModule
# We don't care what the return value of this method is;
# we just need this anonymous class to respond to #name
def name
'Some Name that is not SOReadytohelp'
end
end.new
end
describe '#call_name' do
let(:name) { 'SOReadytohelp' }
before do
allow(my_module_able).to receive(:name).and_return(name)
end
it 'returns the name' do
expect(my_module_able.call_name).to eq(name)
end
end
end
来源:https://stackoverflow.com/questions/32349503/stub-unimplemented-method-in-rspec