如何使 rspec-mocks 期望 receive.with 急切失败
How to make rspec-mocks' expect to receive.with fail eagerly
rspec-mocks' expect(target).to receive(:message).with(arg_matcher)
仅在使用与传递给 with
的 arg 匹配器不匹配的参数调用目标时,才会在测试结束时显示错误。有没有办法强制它急切地失败——即,一旦使用不匹配的参数调用目标? RR是这样工作的。
我面临的问题是,当我如上所述使用 arg_matcher 设置此模拟时,测试开始失败,因为使用不同的参数调用目标,但随后另一个断言在结束之前失败测试,所以我只看到这个断言的错误,而不是丢失的模拟(这会告诉我预期参数和实际调用的参数之间的区别)。
使用 rspec-mocks 3.3.2.
the test starts failing because the target is called with different params, but then another assertion fails before the end of the test, so I only see the error from this assertion, not from the missing mock
如果我没看错,你在一个规范中有多个 expect
断言,而第一个断言失败了,所以你没有看到 second/third 断言失败?
如果是这样,我会考虑使用 RSpec's aggregate_failures
introduced in v3.3,它收集失败但 运行 后续断言:
aggregate_failures("verifying response") do
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "text/plain")
expect(response.body).to include("Success")
end
# Which gives you nice errors for all assertions
1) Client returns a successful response
Got 3 failures:
1.1) Got 3 failures from failure aggregation block "testing response".
# ./spec/use_block_form_spec.rb:18
# ./spec/use_block_form_spec.rb:10
1.1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/use_block_form_spec.rb:19
1.1.2) Failure/Error: expect(response.headers).to include("Content-Type" => "application/json")
expected {"Content-Type" => "text/plain"} to include {"Content-Type" => "application/json"}
Diff:
@@ -1,2 +1,2 @@
-[{"Content-Type"=>"application/json"}]
+"Content-Type" => "text/plain",
# ./spec/use_block_form_spec.rb:20
1.1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/use_block_form_spec.rb:21
1.2) Failure/Error: expect(false).to be(true), "after hook failure"
after hook failure
# ./spec/use_block_form_spec.rb:6
# ./spec/use_block_form_spec.rb:10
1.3) Failure/Error: expect(false).to be(true), "around hook failure"
around hook failure
# ./spec/use_block_form_spec.rb:12
您还可以将描述块标记为 aggregate_failures
:
RSpec.describe ClassName, :aggregate_failures do
# stuff
end
我不知道有什么方法可以让 receive
急切地失败。但是,have_received
急切地失败了,因此如果它是多个期望中的第一个,它将是未通过测试且 RSpec 报告的期望。
class Foo
def self.bar(baz)
end
end
describe "RSpec" do
it "reports a non-mock expectation failure before a mock expectation failure" do
expect(Foo).to receive(:bar).with(1)
expect(true).to be_falsy # RSpec reports this failure
Foo.bar 2
end
it "reports a spy expectation failure when you'd expect it to be reported" do
allow(Foo).to receive(:bar) # Spy on Foo
Foo.bar 2
expect(Foo).to have_received(:bar).with(1) # RSpec reports this failure
expect(true).to be_falsy
end
end
详情见the documentation of RSpec spies。
如果
,这个解决方案可能是最好的
- 如果您喜欢像我一样按逻辑 arrange-act-assert 顺序进行测试
- 如果间谍期望失败,你不关心其他期望
- 如果你介意设置间谍的
allow
的额外输入比你介意 aggregate_failures
块
常规模拟和 Adarsh 的解决方案更好
- 无论是否失败,您都希望看到两种期望的结果
- 如果你介意
aggregate_failures
块比你介意设置间谍的 allow
的额外输入更少
rspec-mocks' expect(target).to receive(:message).with(arg_matcher)
仅在使用与传递给 with
的 arg 匹配器不匹配的参数调用目标时,才会在测试结束时显示错误。有没有办法强制它急切地失败——即,一旦使用不匹配的参数调用目标? RR是这样工作的。
我面临的问题是,当我如上所述使用 arg_matcher 设置此模拟时,测试开始失败,因为使用不同的参数调用目标,但随后另一个断言在结束之前失败测试,所以我只看到这个断言的错误,而不是丢失的模拟(这会告诉我预期参数和实际调用的参数之间的区别)。
使用 rspec-mocks 3.3.2.
the test starts failing because the target is called with different params, but then another assertion fails before the end of the test, so I only see the error from this assertion, not from the missing mock
如果我没看错,你在一个规范中有多个 expect
断言,而第一个断言失败了,所以你没有看到 second/third 断言失败?
如果是这样,我会考虑使用 RSpec's aggregate_failures
introduced in v3.3,它收集失败但 运行 后续断言:
aggregate_failures("verifying response") do
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "text/plain")
expect(response.body).to include("Success")
end
# Which gives you nice errors for all assertions
1) Client returns a successful response
Got 3 failures:
1.1) Got 3 failures from failure aggregation block "testing response".
# ./spec/use_block_form_spec.rb:18
# ./spec/use_block_form_spec.rb:10
1.1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/use_block_form_spec.rb:19
1.1.2) Failure/Error: expect(response.headers).to include("Content-Type" => "application/json")
expected {"Content-Type" => "text/plain"} to include {"Content-Type" => "application/json"}
Diff:
@@ -1,2 +1,2 @@
-[{"Content-Type"=>"application/json"}]
+"Content-Type" => "text/plain",
# ./spec/use_block_form_spec.rb:20
1.1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/use_block_form_spec.rb:21
1.2) Failure/Error: expect(false).to be(true), "after hook failure"
after hook failure
# ./spec/use_block_form_spec.rb:6
# ./spec/use_block_form_spec.rb:10
1.3) Failure/Error: expect(false).to be(true), "around hook failure"
around hook failure
# ./spec/use_block_form_spec.rb:12
您还可以将描述块标记为 aggregate_failures
:
RSpec.describe ClassName, :aggregate_failures do
# stuff
end
我不知道有什么方法可以让 receive
急切地失败。但是,have_received
急切地失败了,因此如果它是多个期望中的第一个,它将是未通过测试且 RSpec 报告的期望。
class Foo
def self.bar(baz)
end
end
describe "RSpec" do
it "reports a non-mock expectation failure before a mock expectation failure" do
expect(Foo).to receive(:bar).with(1)
expect(true).to be_falsy # RSpec reports this failure
Foo.bar 2
end
it "reports a spy expectation failure when you'd expect it to be reported" do
allow(Foo).to receive(:bar) # Spy on Foo
Foo.bar 2
expect(Foo).to have_received(:bar).with(1) # RSpec reports this failure
expect(true).to be_falsy
end
end
详情见the documentation of RSpec spies。
如果
,这个解决方案可能是最好的- 如果您喜欢像我一样按逻辑 arrange-act-assert 顺序进行测试
- 如果间谍期望失败,你不关心其他期望
- 如果你介意设置间谍的
allow
的额外输入比你介意aggregate_failures
块
常规模拟和 Adarsh 的解决方案更好
- 无论是否失败,您都希望看到两种期望的结果
- 如果你介意
aggregate_failures
块比你介意设置间谍的allow
的额外输入更少