2013-11-22 4 views
1

Я пытаюсь понять, почему результат этих испытаний, первый тест утверждает, что метод не был заострен, однако, второй.Устранение ошибки с RSpec

class Roll 
    def initialize 
    install if !installed? 
    end 
    def install; puts 'install'; end 
end 

describe Roll do 
    before do 
    class RollTestClass < Roll; end 
    RollTestClass.any_instance.stub(:install) 
    end 

    let(:roll_class) { RollTestClass } 
    let(:roll) { RollTestClass.new } 

    context 'when installed is true' do 
    before do 
     roll_class.any_instance.stub(:installed?).and_return(true) 
    end 

    it 'should not call install' do 
     expect(roll).to_not have_received(:install) 
    end 
    end 

    context 'when installed is false' do 
    before do 
     roll_class.any_instance.stub(:installed?).and_return(false) 
    end 

    it 'should call install' do 
     expect(roll).to have_received(:install) 
    end 
    end 
end 

Это также странно ошибка говорит expected to have received install, но я думаю, что, скорее всего, просто неисправна обратная связь от DSL RSpec. Но, может быть, стоит отметить.

1) Roll when installed is true should not call install 
    Failure/Error: expect(roll).to_not have_received(:install) 
     #<RollTestClass:0x10f69ef78> expected to have received install, but that method has not been stubbed. 

ответ

2

«Шпионский образец» RSpec требует, чтобы объекты были предварительно заколоты. Однако any_instance.stub фактически не заглушает методы «для реального», если/до тех пор, пока метод не будет вызван на конкретный объект. Таким образом, методы выглядят как «нераскрытые», и вы получаете ошибку, которую получаете. Вот код, который демонстрирует изменение в определении:

class Foo 
end 

describe "" do 
    it "" do 
    Foo.any_instance.stub(:bar) 
    foo1 = Foo.new 
    foo2 = Foo.new 
    print_bars = -> (context) {puts "#{context}, foo1#bar is #{foo1.method(:bar)}, foo2#bar is #{foo2.method(:bar)}"} 
    print_bars['before call'] 
    foo1.bar 
    print_bars['after call'] 
    end 
end 

, который производит следующий вывод:

before call, foo1#bar is #<Method: Foo#bar>, foo2#bar is #<Method: Foo#bar> 
after call, foo1#bar is #<Method: #<Foo:0x007fc0c3842ef8>.bar>, foo2#bar is #<Method: Foo#bar> 

Я сообщил об этом вопрос на GitHub сайте RSpec и получил this acknowledgement/response.

может использовать следующий альтернативный подход, который зависит от недавно введенного метода expect_any_instance_of.

class Roll 
    def initialize 
    install if !installed? 
    end 
    def install; puts 'install'; end 
end 

describe Roll do 
    before do 
    class RollTestClass < Roll; end 
    end 

    let(:roll_class) { RollTestClass } 
    let(:roll) { RollTestClass.new } 

    context 'when installed is true' do 
    before do 
     roll_class.any_instance.stub(:installed?).and_return(true) 
    end 

    it 'should not call install' do 
     expect_any_instance_of(roll_class).to_not receive(:install) 
     roll 
    end 
    end 

    context 'when installed is false' do 
    before do 
     roll_class.any_instance.stub(:installed?).and_return(false) 
    end 

    it 'should call install' do 
     expect_any_instance_of(roll_class).to receive(:install) 
     roll 
    end 
    end 
end 
+0

Отлично! Я решил опубликовать на S.O. а не в rspec-mocks github, потому что я решил, что делаю что-то необычное или неправильно. Хорошо знать его проблему с rspec. Стратегия expect_any_instance_of немного неудобна, но это нужно будет сделать. Благодаря! – brewster

+0

Quick addendum: Если вы используете Mocha для mocks, он «фактически» отключит вызовы при использовании 'any_instance' – Neal

Смежные вопросы