我正在测试我的模块,我决定测试它与匿名类:
subject(:klass) { Class.new { include MyModule } }
MyModule
使用name
内的方法klass
。为了让我的规范工作,我需要存根这个方法name
(未实现)。所以我写道:
subject { klass.new }
allow(subject).to receive(:name).and_return('SOreadytohelp') }
但它提出了:
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>'
如何在不定义的情况下存根此方法?
答案 0 :(得分:5)
RSpec引发了这个异常,因为对原始对象上不存在的方法进行存根是没有用的。
模拟方法总是容易出错,因为模拟的行为可能与原始实现不同,因此即使原始实现返回错误(或者甚至不存在),规范也可能成功。允许模拟不存在的方法是完全错误的。
因此我认为你不应该试图绕过这个例外。只需在您的类中添加name
方法,如果在测试环境之外运行,则会引发明确的异常:
def self.name
raise NoMethodError # TODO: check specs...
end
答案 1 :(得分:3)
subject(:klass) do
Struct.new(:name) do
include MyModule
end
end
答案 2 :(得分:1)
我认为如果你正在编写的测试集中在你的MyModule
模块上,并且该模块依赖于它所混合的类中的实例方法,那么我认为该方法应该被模拟出来在测试模块时使用的匿名类中。例如:
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