问题描述
在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 usingexpect
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 使用allow
.
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
double 永远不会代表Foo.bar(baz)
的结果,因此从来没有#qux
调用它expect
规范在Foo
从未收到.bar(baz)
的地方失败,所以我们甚至没有达到这一点询问foobar_result
double- The
allow
spec fails because thefoobar_result
double never gets to stand in for the result ofFoo.bar(baz)
, and hence never has#qux
called on it - The
expect
spec fails at the point ofFoo
never receiving.bar(baz)
so we don't even get to the point of interrogating thefoobar_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
以在它收到 :bar
和 baz 时返回
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)
...你也在做同样的事情,加上告诉规范失败unless
Foo
用 baz 接收
:bar
.
... you're doing the same, plus telling the spec to fail unless
Foo
receives :bar
with baz
.
要查看不同之处,请在
Foo
not 接收 :bar
和 baz
的示例中尝试两者.
To see the difference, try both in examples where
Foo
does not receive :bar
with baz
.
这篇关于RSpec 允许/期望与仅期望/和返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!