RSpec allow/expect 对比 expect/and_return
RSpec allow/expect vs just expect/and_return
在RSpec中,具体版本>=3,有什么区别:
- 使用
allow
设置消息预期,参数为 return 测试替身,然后使用 expect
对 return 测试替身做出断言
- 只需使用
expect
设置带参数的期望和 return 测试替身
还是只是语义?我知道 providing/specifying return 值 expect
是 the syntax in RSpec mocks 2.13, but as far as I can see, 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)>'
那么,这两个测试之间是否存在任何真正的差异,无论是结果还是表达的意图,或者只是语义 and/or 个人偏好? allow
/expect
是否应该在 expect
/and_return
上使用,因为它看起来像是替换语法,或者它们中的每一个都应该用于特定的测试场景?
更新
看完之后,我注释掉了上面示例代码中的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
double 永远无法代替 Foo.bar(baz)
的结果,因此 #qux
也从未调用它
expect
规范在 Foo
从未收到 .bar(baz)
时失败,因此我们甚至没有达到询问 foobar_result
double
有道理:这不仅仅是语法更改,而且 expect
/and_return
的目的确实不同于 allow
/expect
。我真的应该检查最明显的地方:RSpec Mocks README,特别是以下部分:
看经典文章Mocks Aren't Stubs。 allow
制作存根,而 expect
制作模拟。也就是说 allow
允许一个对象 return X 而不是任何它会 return unstubbed 的对象,并且 expect
是一个 allow
plus 对某些状态或事件的期望。当你写
allow(Foo).to receive(:bar).with(baz).and_return(foobar_result)
...您告诉规范环境在收到 :bar
和 baz
时将 Foo
修改为 return foobar_result
。但是当你写
expect(Foo).to receive(:bar).with(baz).and_return(foobar_result)
...您正在做同样的事情,并告诉规范失败 除非 Foo
收到 :bar
和 baz
。
要查看差异,请在 Foo
不 接收 :bar
和 baz
的示例中尝试两者。
在RSpec中,具体版本>=3,有什么区别:
- 使用
allow
设置消息预期,参数为 return 测试替身,然后使用expect
对 return 测试替身做出断言 - 只需使用
expect
设置带参数的期望和 return 测试替身
还是只是语义?我知道 providing/specifying return 值 expect
是 the syntax in RSpec mocks 2.13, but as far as I can see, 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)>'
那么,这两个测试之间是否存在任何真正的差异,无论是结果还是表达的意图,或者只是语义 and/or 个人偏好? allow
/expect
是否应该在 expect
/and_return
上使用,因为它看起来像是替换语法,或者它们中的每一个都应该用于特定的测试场景?
更新
看完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
double 永远无法代替Foo.bar(baz)
的结果,因此#qux
也从未调用它expect
规范在Foo
从未收到.bar(baz)
时失败,因此我们甚至没有达到询问foobar_result
double
有道理:这不仅仅是语法更改,而且 expect
/and_return
的目的确实不同于 allow
/expect
。我真的应该检查最明显的地方:RSpec Mocks README,特别是以下部分:
看经典文章Mocks Aren't Stubs。 allow
制作存根,而 expect
制作模拟。也就是说 allow
允许一个对象 return X 而不是任何它会 return unstubbed 的对象,并且 expect
是一个 allow
plus 对某些状态或事件的期望。当你写
allow(Foo).to receive(:bar).with(baz).and_return(foobar_result)
...您告诉规范环境在收到 :bar
和 baz
时将 Foo
修改为 return foobar_result
。但是当你写
expect(Foo).to receive(:bar).with(baz).and_return(foobar_result)
...您正在做同样的事情,并告诉规范失败 除非 Foo
收到 :bar
和 baz
。
要查看差异,请在 Foo
不 接收 :bar
和 baz
的示例中尝试两者。