2015-09-02 2 views
6

Я проверяю мой модуль, и я решил проверить это против анонимного класса:Заглушки невыполненного метод RSpec

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

Я не знаю, если это ответ, но у вас есть опечатка; 'subjet {klass.new}'. Не должно быть: 'subject {klass.new}' (отсутствует 'c'). Попробуйте это и сообщите нам! –

ответ

3

RSpec поднимает это исключение, потому что это не полезно незавершенным метод, который не существует на исходном объекте.

Методы откусов всегда подвержены ошибкам, поскольку макет может вести себя иначе, чем исходная реализация, и поэтому спецификации могут быть успешными, даже если исходная реализация вернет ошибку (или даже не существует). Предотвращение издевательства несуществующих методов просто неверно.

Поэтому я бы сказал, что вы не должны пытаться обойти это исключение. Просто добавьте name метод в класс, который вызывает четкое исключение, если работать вне тестовой среды:

def self.name 
    raise NotImplementedError # TODO: check specs... 
end 
+0

'name' должен, вероятно, быть методом экземпляра, возвращающим' 'SOreadytohelp'' – Stefan

+0

@Stefan: Я согласен, это тоже хорошая идея. Зависит от фокуса: Чтобы подчеркнуть, что спецификации и код синхронизированы или что-то можно исправить ... – spickermann

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 
Смежные вопросы