2015-01-18 2 views
22

В RSpec, в частности, версия> = 3, есть ли разница между:RSpec разрешить/ожидать против просто ожидать/and_return

  • Использование allow для установки ожидания сообщения с параметрами, которые возвращают тестовые двойников, а затем с помощью expect сделать утверждение о возвращенном тесте удваивается
  • Просто используя expect настроить ожидания с параметрами и вернуть тест двойной

или все это просто семантика? Я знаю, что предоставление/указание возвращаемого значения с expect было the syntax in RSpec mocks 2.13, но, насколько я вижу, the syntax changed in RSpec mocks 3 использовать allow.

Однако в (прохождение) образец кода ниже, с использованием либо allow/expect или просто expect/and_return кажется, чтобы генерировать один и тот же результат. Если один синтаксис был предпочитать другой, возможно, я бы ожидал там быть какой-то устаревания уведомления, но так как это не так, то, казалось бы, что оба Синтаксисы считаются действительными:

class Foo 
    def self.bar(baz) 
    # not important what happens to baz parameter 
    # only important that it is passed in 
    new 
    end 

    def qux 
    # perform some action 
    end 
end 

class SomethingThatCallsFoo 
    def some_long_process(baz) 
    # do some processing 
    Foo.bar(baz).qux 
    # do other processing 
    end 
end 

describe SomethingThatCallsFoo do 
    let(:foo_caller) { SomethingThatCallsFoo.new } 

    describe '#some_long_process' do 
    let(:foobar_result) { double('foobar_result') } 
    let(:baz) { double('baz') } 

    context 'using allow/expect' do 
     before do 
     allow(Foo).to receive(:bar).with(baz).and_return(foobar_result) 
     end 

     it 'calls qux method on result of Foo.bar(baz)' do 
     expect(foobar_result).to receive(:qux) 
     foo_caller.some_long_process(baz) 
     end 
    end 

    context 'using expect/and_return' do 
     it 'calls qux method on result of Foo.bar(baz)' do 
     expect(Foo).to receive(:bar).with(baz).and_return(foobar_result) 
     expect(foobar_result).to receive(:qux) 
     foo_caller.some_long_process(baz) 
     end 
    end 
    end 
end 

Если я сознательно сделать что тесты не путем изменения Переданного baz параметра в ожидании на другой двойной тест, ошибки в значительной степени то же самое:

1) SomethingThatCallsFoo#some_long_process using allow/expect calls quux method on result of Foo.bar(baz) 
    Failure/Error: Foo.bar(baz).qux 
     <Foo (class)> received :bar with unexpected arguments 
     expected: (#<RSpec::Mocks::Double:0x3fe97a0127fc @name="baz">) 
       got: (#<RSpec::Mocks::Double:0x3fe97998540c @name=nil>) 
     Please stub a default value first if message might be received with other args as well. 
    # ./foo_test.rb:16:in `some_long_process' 
    # ./foo_test.rb:35:in `block (4 levels) in <top (required)>' 

    2) SomethingThatCallsFoo#some_long_process using expect/and_return calls quux method on result of Foo.bar(baz) 
    Failure/Error: Foo.bar(baz).qux 
     <Foo (class)> received :bar with unexpected arguments 
     expected: (#<RSpec::Mocks::Double:0x3fe979935fd8 @name="baz">) 
       got: (#<RSpec::Mocks::Double:0x3fe979cc5c0c @name=nil>) 
    # ./foo_test.rb:16:in `some_long_process' 
    # ./foo_test.rb:43:in `block (4 levels) in <top (required)>' 

Итак, есть ли какие-либо реальные различия между этими двумя тестами, либо в результате или выраженное намерение, или это просто семантика и/или личное предпочтение? Должен ли allow/expect использоваться по сравнению с expect/and_return в целом, поскольку он выглядит синтаксисом замены или каждый из них предназначен для использования в конкретных тестовых сценариях?

Update

После прочтения Mori's answer «с, я закомментировал Foo.bar(baz).qux строки из кода примера выше, и получили следующие ошибки:

1) SomethingThatCallsFoo#some_long_process using allow/expect calls qux method on result of Foo.bar(baz) 
    Failure/Error: expect(foobar_result).to receive(:qux) 
     (Double "foobar_result").qux(any args) 
      expected: 1 time with any arguments 
      received: 0 times with any arguments 
    # ./foo_test.rb:34:in `block (4 levels) in <top (required)>' 

    2) SomethingThatCallsFoo#some_long_process using expect/and_return calls qux method on result of Foo.bar(baz) 
    Failure/Error: expect(Foo).to receive(:bar).with(baz).and_return(foobar_result) 
     (<Foo (class)>).bar(#<RSpec::Mocks::Double:0x3fc211944fa4 @name="baz">) 
      expected: 1 time with arguments: (#<RSpec::Mocks::Double:0x3fc211944fa4 @name="baz">) 
      received: 0 times 
    # ./foo_test.rb:41:in `block (4 levels) in <top (required)>' 
  • allow спецификации терпит неудачу, потому что foobar_result Двойной никогда не заходит за результат Foo.bar(baz), и, следовательно, никогда не имеет #qux, вызвавшего его
  • expect спекуляция терпит неудачу в точке Foo никогда не получать .bar(baz) так что мы даже не добраться до точки допрашивать foobar_result двойной

Имеет смысл: это не просто изменение синтаксиса, и что expect/and_return действительно имеет цель отличается от allow/expect.Я действительно должен был проверить самое очевидное место: RSpec Mocks README, в частности, следующие разделы:

ответ

58

См классическую статью Mocks Aren't Stubs. allow делает заглушку, а expect делает насмешливый. То есть allow позволяет объекту вернуть X вместо того, что бы он не возвращал, и expect является allowplus Ожидание какого-либо состояния или события. Когда вы пишете

allow(Foo).to receive(:bar).with(baz).and_return(foobar_result) 

... вы говорите спецификации среды для изменения Foo вернуть foobar_result, когда он получает :bar с baz. Но когда вы пишете

expect(Foo).to receive(:bar).with(baz).and_return(foobar_result) 

... вы делаете то же самое, плюс говоря спецификации потерпеть неудачу еслиFoo не получает :bar с baz.

Чтобы увидеть разницу, попробуйте как в примерах, где Foo делает не получить :bar с baz.

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

  • Нет связанных вопросов^_^