RSpec 允许/期望与仅期望/and_return [英] RSpec allow/expect vs just expect/and_return

查看:35
本文介绍了RSpec 允许/期望与仅期望/and_return的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 RSpec,特别是版本 >= 3 中,有什么区别:

In RSpec, specifically version >= 3, is there any difference between:

  • 使用 allow 设置带有返回测试替身的参数的消息预期,然后使用 expect 对返回的测试替身进行断言
  • 只需使用 expect 设置带参数的期望并返回测试替身
  • Using allow to set up message expectations with parameters that return test doubles, and then using expect to make an assertion on the returned test doubles
  • Just using expect to set up the expectation with parameters and return the test double

还是只是语义?我知道使用 expect 提供/指定返回值是 RSpec 模拟 2.13 中的语法,但据我所知,RSpec 模拟中更改的语法3 使用允许.

or is it all just semantics? I know that providing/specifying a return value with expect was the syntax in RSpec mocks 2.13, but as far as I can see, the syntax changed in RSpec mocks 3 to use allow.

但是,在下面的(通过)示例代码中,使用 allow/expect 或仅使用 expect/and_return 似乎产生了相同的结果.如果一种语法比另一种更受青睐,也许我会期望会有某种弃用通知,但既然没有,这两种语法似乎都被认为是有效的:

However, in the (passing) sample code below, using either allow/expect or just expect/and_return seems to generate the same result. If one syntax was favoured over another, perhaps I would have expected there to be some kind of deprecation notice, but since there isn't, it would seem that both syntaxes are considered valid:

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 参数更改为不同的测试替身来使测试失败,则错误几乎相同:

If I deliberately make the tests fail by changing the passed-in baz parameter in the expectation to a different test double, the errors are pretty much the same:

  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 上使用,因为它看起来像是替换语法,或者它们中的每一个都是为了在特定的测试场景中使用吗?

So, are there any real differences between these two tests, either in result or expressed intent, or is it just semantics and/or personal preference? Should allow/expect be used over expect/and_return in general as it seems like it's the replacement syntax, or are each of them meant to be used in specific test scenarios?

更新

在阅读了 Mori 的回答之后,我注释掉了 Foo.bar(baz).qux 从上面的示例代码行,并得到以下错误:

After reading Mori's answer's, I commented out the Foo.bar(baz).qux line from the example code above, and got the following errors:

  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 double
    • The allow spec fails because the foobar_result double never gets to stand in for the result of Foo.bar(baz), and hence never has #qux called on it
    • The expect spec fails at the point of Foo never receiving .bar(baz) so we don't even get to the point of interrogating the foobar_result double
    • 有道理:这不仅仅是语法更改,而且 expect/and_return 确实有不同于 allow/ 的目的期待.我真的应该检查最明显的地方:RSpec Mocks README,具体如下:

      Makes sense: it's not just a syntax change, and that expect/and_return does have a purpose different to allow/expect. I really should have checked the most obvious place: the RSpec Mocks README, specifically the following sections:

      推荐答案

      参见经典文章 Mocks Aren't Stubs.allow 做一个存根,而 expect 做一个模拟.那就是 allow 允许一个对象返回 X 而不是它会返回 unstubbed 的任何东西,并且 expect 是一个 allow plus 对某种状态或事件的期望.当你写

      See the classic article Mocks Aren't Stubs. allow makes a stub while expect makes a mock. That is allow allows an object to return X instead of whatever it would return unstubbed, and expect is an allow plus an expectation of some state or event. When you write

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

      ...您告诉规范环境修改 Foo 以在收到 :barbaz 时返回 foobar_result.但是当你写

      ... you're telling the spec environment to modify Foo to return foobar_result when it receives :bar with baz. But when you write

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

      ...你也在做同样的事情,加上告诉规范失败 除非 Foo 接收 :barbaz.

      ... you're doing the same, plus telling the spec to fail unless Foo receives :bar with baz.

      要查看差异,请尝试在 Foo 确实 not 接收 :barbaz 的示例中.

      To see the difference, try both in examples where Foo does not receive :bar with baz.

      这篇关于RSpec 允许/期望与仅期望/and_return的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆