RSpec允许/期望vs期望/和_return
在RSpec中,特别是版本> = 3,之间有什么区别:
- 使用
allow
来设置返回测试双精度的参数的消息期望,然后使用expect
对返回的测试双精度进行断言 - 只需使用
expect
来设置参数的期望并返回测试double
或者只是语义学? 我知道提供/指定带有expect
的返回值是RSpec模拟2.13中的语法 ,但据我所知,RSpec模拟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
参数更改为不同的测试double来使测试失败,则错误几乎相同:
1) SomethingThatCallsFoo#some_long_process using allow/expect calls quux method on result of Foo.bar(baz) Failure/Error: Foo.bar(baz).qux received :bar with unexpected arguments expected: (#) got: (#) 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 ' 2) SomethingThatCallsFoo#some_long_process using expect/and_return calls quux method on result of Foo.bar(baz) Failure/Error: Foo.bar(baz).qux received :bar with unexpected arguments expected: (#) got: (#) # ./foo_test.rb:16:in `some_long_process' # ./foo_test.rb:43:in `block (4 levels) in '
那么,这两个测试之间是否有任何真正的差异,无论是结果还是表达意图,还是只是语义和/或个人偏好? 应该allow
/ expect
通常使用expect
/ and_return
,因为它似乎是替换语法,或者它们中的每一个是否都用于特定的测试场景?
更新
在阅读了Mori的答案之后,我从上面的示例代码中注释掉了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 ' 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) ().bar(#) expected: 1 time with arguments: (#) received: 0 times # ./foo_test.rb:41:in `block (4 levels) in '
-
allow
规范失败,因为foobar_result
double永远不会代表Foo.bar(baz)
的结果,因此从来没有#qux
调用它 -
expect
规格在Foo
永远不会收到.bar(baz)
失败,所以我们甚至没有到达审讯foobar_result
double的程度
有道理:它不仅仅是语法更改,而且expect
/ and_return
确实具有与allow
/ expect
不同的目的。 我真的应该检查一下最明显的地方: RSpec Mocks README ,特别是以下几节:
- 模拟对象和测试存根
- 特定于测试的扩展
- 设置回复
请参阅经典文章Mocks Are Not Stubs 。 allow
使用存根而expect
进行模拟。 那就是allow
一个对象返回X而不是它将返回的任何东西,并且expect
是一个allow
加上一些状态或事件的期望。 当你写作
allow(Foo).to receive(:bar).with(baz).and_return(foobar_result)
…你告诉规范环境修改Foo
以在收到时返回foobar_result
:bar
with baz
。 但是当你写作
expect(Foo).to receive(:bar).with(baz).and_return(foobar_result)
…你正在做同样的事情,加上告诉规范失败, 除非 Foo
收到:bar
与baz
。
要查看差异,请在Foo
未收到的示例中尝试:bar
with baz
。
- Rails RSpec路由:测试操作:除了不路由
- Rspec 3.未定义的局部变量或方法`response’for#
- 未定义的局部变量或方法 – 使用Beaker测试Puppet模块
- 从before(:each)块中获取完整的RSpec测试名称
- rspec,未知属性问题
- RailsTutorial 3.2 Ch 9 – “before {valid_signin(user)}”导致RSpec测试失败
- RSpec :: ExampleGroups :: User :: Validations的未定义方法`validate_presence_of’
- rspec +工厂模型测试嵌套属性
- 如何使用rspec测试mandrill api