聚合失败
RSpec::Expectations 提供了 aggregate_failures
,这是一个 API,允许您对一组期望进行分组,并在一次查看所有失败,而不是在第一个失败时中止。RSpec::Core 在几个方面改进了此功能
* RSpec::Core provides much better failure output, adding code snippets and backtraces to the sub-failures, just like it does for any normal failure.
* RSpec::Core provides [metadata](../metadata/user-defined-metadata) integration for this feature. Each example that is tagged with `:aggregate_failures` will be wrapped in an `aggregate_failures` block. You can also use `config.define_derived_metadata` to apply this to every example automatically.
元数据形式非常方便,但可能不适用于具有多个不同步骤的端到端测试。例如,考虑一个 HTTP 客户端工作流程的规范,该工作流程(1)发出请求,(2)预期重定向,(3)遵循重定向,以及(4)预期特定响应。您可能希望 `expect(response.status).to be_between(300, 399)` 期望在失败时立即中止,因为如果该期望不满足,您无法执行下一步(遵循重定向)。对于这些情况,我们建议您使用 `aggregate_failures` 块形式来包装代表测试工作流程中不同步骤的每组期望。
背景
给定一个名为“lib/client.rb”的文件,内容为
Response = Struct.new(:status, :headers, :body)
class Client
def self.make_request(url='/')
Response.new(404, { "Content-Type" => "text/plain" }, "Not Found")
end
end
使用 `aggregate_failures` 块形式
给定一个名为“spec/use_block_form_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
after do
# this should be appended to failure list
expect(false).to be(true), "after hook failure"
end
around do |ex|
ex.run
# this should also be appended to failure list
expect(false).to be(true), "around hook failure"
end
it "returns a successful response" do
response = Client.make_request
aggregate_failures "testing response" do
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.body).to eq('{"message":"Success"}')
end
end
end
当我运行 `rspec spec/use_block_form_spec.rb`
那么它应该失败并列出所有失败
Failures:
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 +1 @@
-"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` 块形式
给定一个名为“spec/use_block_form_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
after do
# this should be appended to failure list
expect(false).to be(true), "after hook failure"
end
around do |ex|
ex.run
# this should also be appended to failure list
expect(false).to be(true), "around hook failure"
end
it "returns a successful response" do
response = Client.make_request
aggregate_failures "testing response" do
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.body).to eq('{"message":"Success"}')
end
end
end
当我运行 `rspec spec/use_block_form_spec.rb`
那么它应该失败并列出所有失败
Failures:
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` 元数据
给定一个名为“spec/use_metadata_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
it "follows a redirect", :aggregate_failures do
response = Client.make_request
expect(response.status).to eq(302)
expect(response.body).to eq('{"message":"Redirect"}')
redirect_response = Client.make_request(response.headers.fetch('Location'))
expect(redirect_response.status).to eq(200)
expect(redirect_response.body).to eq('{"message":"OK"}')
end
end
当我运行 `rspec spec/use_metadata_spec.rb`
那么它应该失败并列出所有失败
Failures:
1) Client follows a redirect
Got 2 failures and 1 other error:
1.1) Failure/Error: expect(response.status).to eq(302)
expected: 302
got: 404
(compared using ==)
# ./spec/use_metadata_spec.rb:7
1.2) Failure/Error: expect(response.body).to eq('{"message":"Redirect"}')
expected: "{\"message\":\"Redirect\"}"
got: "Not Found"
(compared using ==)
# ./spec/use_metadata_spec.rb:8
1.3) Failure/Error: redirect_response = Client.make_request(response.headers.fetch('Location'))
KeyError:
key not found: "Location"
# ./spec/use_metadata_spec.rb:10
# ./spec/use_metadata_spec.rb:10
使用 `define_derived_metadata` 在全局启用失败聚合
给定一个名为“spec/enable_globally_spec.rb”的文件,内容为
require 'client'
RSpec.configure do |c|
c.define_derived_metadata do |meta|
meta[:aggregate_failures] = true
end
end
RSpec.describe Client do
it "returns a successful response" do
response = Client.make_request
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.body).to eq('{"message":"Success"}')
end
end
当我运行 `rspec spec/enable_globally_spec.rb`
那么它应该失败并列出所有失败
Failures:
1) Client returns a successful response
Got 3 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/enable_globally_spec.rb:13
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 +1 @@
-"Content-Type" => "application/json",
+"Content-Type" => "text/plain",
# ./spec/enable_globally_spec.rb:14
1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/enable_globally_spec.rb:15
使用 `define_derived_metadata` 在全局启用失败聚合
给定一个名为“spec/enable_globally_spec.rb”的文件,内容为
require 'client'
RSpec.configure do |c|
c.define_derived_metadata do |meta|
meta[:aggregate_failures] = true
end
end
RSpec.describe Client do
it "returns a successful response" do
response = Client.make_request
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.body).to eq('{"message":"Success"}')
end
end
当我运行 `rspec spec/enable_globally_spec.rb`
那么它应该失败并列出所有失败
Failures:
1) Client returns a successful response
Got 3 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/enable_globally_spec.rb:13
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/enable_globally_spec.rb:14
1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/enable_globally_spec.rb:15
嵌套的失败聚合有效
给定一个名为“spec/nested_failure_aggregation_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
it "returns a successful response", :aggregate_failures do
response = Client.make_request
expect(response.status).to eq(200)
aggregate_failures "testing headers" do
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.headers).to include("Content-Length" => "21")
end
expect(response.body).to eq('{"message":"Success"}')
end
end
当我运行 `rspec spec/nested_failure_aggregation_spec.rb`
那么它应该失败并列出所有失败
Failures:
1) Client returns a successful response
Got 3 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/nested_failure_aggregation_spec.rb:7
1.2) Got 2 failures from failure aggregation block "testing headers".
# ./spec/nested_failure_aggregation_spec.rb:9
1.2.1) Failure/Error: expect(response.headers).to include("Content-Type" => "application/json")
expected {"Content-Type" => "text/plain"} to include {"Content-Type" => "application/json"}
Diff:
@@ -1 +1 @@
-"Content-Type" => "application/json",
+"Content-Type" => "text/plain",
# ./spec/nested_failure_aggregation_spec.rb:10
1.2.2) Failure/Error: expect(response.headers).to include("Content-Length" => "21")
expected {"Content-Type" => "text/plain"} to include {"Content-Length" => "21"}
Diff:
@@ -1 +1 @@
-"Content-Length" => "21",
+"Content-Type" => "text/plain",
# ./spec/nested_failure_aggregation_spec.rb:11
1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/nested_failure_aggregation_spec.rb:14
嵌套的失败聚合有效
给定一个名为“spec/nested_failure_aggregation_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
it "returns a successful response", :aggregate_failures do
response = Client.make_request
expect(response.status).to eq(200)
aggregate_failures "testing headers" do
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.headers).to include("Content-Length" => "21")
end
expect(response.body).to eq('{"message":"Success"}')
end
end
当我运行 `rspec spec/nested_failure_aggregation_spec.rb`
那么它应该失败并列出所有失败
Failures:
1) Client returns a successful response
Got 3 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/nested_failure_aggregation_spec.rb:7
1.2) Got 2 failures from failure aggregation block "testing headers".
# ./spec/nested_failure_aggregation_spec.rb:9
1.2.1) 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/nested_failure_aggregation_spec.rb:10
1.2.2) Failure/Error: expect(response.headers).to include("Content-Length" => "21")
expected {"Content-Type" => "text/plain"} to include {"Content-Length" => "21"}
Diff:
@@ -1,2 +1,2 @@
-"Content-Length" => "21",
+"Content-Type" => "text/plain",
# ./spec/nested_failure_aggregation_spec.rb:11
1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/nested_failure_aggregation_spec.rb:14
模拟期望失败也聚合
给定一个名为“spec/mock_expectation_failure_spec.rb”的文件,内容为
require 'client'
RSpec.describe "Aggregating Failures", :aggregate_failures do
it "has a normal expectation failure and a message expectation failure" do
client = double("Client")
expect(client).to receive(:put).with("updated data")
allow(client).to receive(:get).and_return(Response.new(404, {}, "Not Found"))
response = client.get
expect(response.status).to eq(200)
end
end
当我运行 `rspec spec/mock_expectation_failure_spec.rb`
那么它应该失败并列出所有失败
Failures:
1) Aggregating Failures has a normal expectation failure and a message expectation failure
Got 2 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/mock_expectation_failure_spec.rb:10
1.2) Failure/Error: expect(client).to receive(:put).with("updated data")
(Double "Client").put("updated data")
expected: 1 time with arguments: ("updated data")
received: 0 times
# ./spec/mock_expectation_failure_spec.rb:6
待处理示例与聚合失败良好集成
给定一个名为“spec/pending_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
it "returns a successful response", :aggregate_failures do
pending "Not yet ready"
response = Client.make_request
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.body).to eq('{"message":"Success"}')
end
end
当我运行 `rspec spec/pending_spec.rb`
那么它应该通过并列出所有待处理示例
Pending: (Failures listed here are expected and do not affect your suite's status)
1) Client returns a successful response
# Not yet ready
Got 3 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/pending_spec.rb:8
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 +1 @@
-"Content-Type" => "application/json",
+"Content-Type" => "text/plain",
# ./spec/pending_spec.rb:9
1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/pending_spec.rb:10
待处理示例与聚合失败良好集成
给定一个名为“spec/pending_spec.rb”的文件,内容为
require 'client'
RSpec.describe Client do
it "returns a successful response", :aggregate_failures do
pending "Not yet ready"
response = Client.make_request
expect(response.status).to eq(200)
expect(response.headers).to include("Content-Type" => "application/json")
expect(response.body).to eq('{"message":"Success"}')
end
end
当我运行 `rspec spec/pending_spec.rb`
那么它应该通过并列出所有待处理示例
Pending: (Failures listed here are expected and do not affect your suite's status)
1) Client returns a successful response
# Not yet ready
Got 3 failures:
1.1) Failure/Error: expect(response.status).to eq(200)
expected: 200
got: 404
(compared using ==)
# ./spec/pending_spec.rb:8
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/pending_spec.rb:9
1.3) Failure/Error: expect(response.body).to eq('{"message":"Success"}')
expected: "{\"message\":\"Success\"}"
got: "Not Found"
(compared using ==)
# ./spec/pending_spec.rb:10