モジュールをテストしていて、匿名クラスと比較してテストすることにしました。
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>'
このメソッドを定義せずにスタブする方法は?
元のオブジェクトに存在しないメソッドをスタブ化することは役に立たないため、RSpecはこの例外を発生させます。
モックは元の実装とは異なる動作をする可能性があるため、モックメソッドは常にエラーが発生しやすく、元の実装がエラーを返した(または存在しなかった)場合でも仕様は成功する可能性があります。存在しないメソッドをモックすることを許可することは、まったく間違っています。
したがって、この例外を回避しようとすべきではないと私は主張します。 name
メソッドをクラスに追加するだけで、テスト環境の外部で実行すると明確な例外が発生します。
def self.name
raise NoMethodError # TODO: check specs...
end
subject(:klass) do
Struct.new(:name) do
include MyModule
end
end
あなたが書いているテストがあなたの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