RubyのObject#then
Object#then (Ruby 3.1 リファレンスマニュアル)
yield_self のエイリアス。selfを引数としてブロックを評価し、ブロックの結果を返す
# thenを使うと
# これを
def user_name(user, hage)
first_name = user.fetch(:first_name, {})
first_name.empty? ? first_name : first_name.merge(last_name:)
end
# こう書ける
def user_name(user, hage)
user.fetch(:first_name, {}).then { |name| name.empty? ? name : name.merge(last_name:) }
first_name.empty? ? {} : first_name.merge(last_name:)
end
aggregate_failures
https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-failures
1つのexampleに複数のexpectがあるとき、途中のexpectがfailしてしまうと後続のexpectは実行されない
そうなると後続のexpectは期待結果どおりになったのかがわからなくなってしまう
後続のexpectがエラーになっていたとしたら1個ずつ直していかなければいけない
この問題を解決するのが aggregate_failures
こんなかんじでブロックで囲んだexpectをすべて実行してくれる
it 'レスポンスが正しい値であること' do
aggregate_failures do
expect(response).to have_http_status(:success)
expect(response.body).to include book.title
end
end
また、文字列を渡すとブロックのラベルとしてテスト結果に出力されるので、まとまりが視認しやすくなる
以下、https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-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
これを実行すると以下のように出力される
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をすべてのテストに適用する
cf. 実用的な新機能が盛りだくさん!RSpec 3.3 完全ガイド - Qiita
spec_helper.rbに以下の設定を追加すると、すべてのテストでaggregate_failuresが適用される
RSpec.configure do |config|
config.define_derived_metadata do |meta|
meta[:aggregate_failures] = true unless meta.key?(:aggregate_failures)
end
end
一部だけ無効にしたい場合は、 aggregate_failures: false を付ける
it "returns a successful response", aggregate_failures: false 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