メインコンテンツまでスキップ

マッチャーの組み合わせ

RSpecのマッチャーは、組み合わせて使用することができるように設計されています。これにより、期待する内容の正確な詳細を表現することができますが、それ以上のことは表現しません。これにより、過剰に指定された脆弱な仕様を書くことを避けることができます。マッチャーを使用して、期待する内容の本質的な側面のみを指定します。

以下のマッチャーは、マッチャーを引数として受け入れます。

  • change { }.by(matcher)
  • change { }.from(matcher).to(matcher)
  • contain_exactly(matcher, matcher, matcher)
  • end_with(matcher, matcher)
  • include(matcher, matcher)
  • include(:key => matcher, :other => matcher)
  • match(arbitrary_nested_structure_with_matchers)
  • output(matcher).to_stdout
  • output(matcher).to_stderr
  • raise_error(ErrorClass, matcher)
  • start_with(matcher, matcher)
  • throw_symbol(:sym, matcher)
  • yield_with_args(matcher, matcher)
  • yield_successive_args(matcher, matcher)

多くの組み込みマッチャーは、マッチャー引数を受け入れないようになっています。これは、厳密な意味論を持ち、マッチャー引数を許容しないためです。例えば、equal(some_object)は、実際の引数と期待する引数が同じオブジェクトへの参照である場合にのみパスするように設計されています。ここでは、マッチャー引数をサポートすることは意味がありません。

RSpecの組み込みマッチャーは、名詞句を使用して動詞形ではなく使用することができる1つ以上のエイリアスを持っています。また、失敗時の出力もカスタマイズされており、失敗メッセージも読みやすくなっています。

これらのエイリアスの完全なリストはここでは範囲外ですが、以下にいくつかの使用例を示します。

  • be < 2 => a_value < 2
  • be > 2 => a_value > 2
  • be_an_instance_of => an_instance_of
  • be_within => a_value_within
  • contain_exactly => a_collection_containing_exactly
  • end_with => a_string_ending_with, ending_with
  • match => a_string_matching
  • start_with => a_string_starting_with

完全なリストについては、RSpec::MatchersモジュールのAPIドキュメントを参照してください。

changeを使ったマッチャの組み合わせ

ファイル名が「change_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `change`" do
specify "you can pass a matcher to `by`" do
k = 0
expect { k += 1.05 }.to change { k }.
by( a_value_within(0.1).of(1.0) )
end

specify "you can pass matchers to `from` and `to`" do
s = "food"
expect { s = "barn" }.to change { s }.
from( a_string_matching(/foo/) ).
to( a_string_matching(/bar/) )
end
end

rspec change_spec.rbを実行した場合、

全ての例がパスするはずです。

contain_exactlyを使ったマッチャの組み合わせ

ファイル名が「contain_exactly_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `contain_exactly`" do
specify "you can pass matchers in place of exact values" do
expect(["barn", 2.45]).to contain_exactly(
a_value_within(0.1).of(2.5),
a_string_starting_with("bar")
)
end
end

rspec contain_exactly_spec.rbを実行した場合、

全ての例がパスするはずです。

end_withを使ったマッチャの組み合わせ

ファイル名が「end_with_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `end_with`" do
specify "you can pass matchers in place of exact values" do
expect(["barn", "food", 2.45]).to end_with(
a_string_matching("foo"),
a_value > 2
)
end
end

rspec end_with_spec.rbを実行した場合、

全ての例がパスするはずです。

includeを使ったマッチャの組み合わせ

ファイル名が「include_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `include`" do
specify "you can use matchers in place of array values" do
expect(["barn", 2.45]).to include( a_string_starting_with("bar") )
end

specify "you can use matchers in place of hash values" do
expect(:a => "food", :b => "good").to include(:a => a_string_matching(/foo/))
end

specify "you can use matchers in place of hash keys" do
expect("food" => "is good").to include( a_string_matching(/foo/) )
end
end

rspec include_spec.rbを実行した場合、

全ての例がパスするはずです。

matchを使ったマッチャの組み合わせ

ファイル名が「match_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `match`" do
specify "you can match nested data structures against matchers" do
hash = {
:a => {
:b => ["foo", 5.0],
:c => { :d => 2.05 }
}
}

expect(hash).to match(
:a => {
:b => a_collection_containing_exactly(
a_string_starting_with("f"),
an_instance_of(Float)
),
:c => { :d => (a_value < 3) }
}
)
end
end

rspec match_spec.rbを実行した場合、

全ての例がパスするはずです。

outputを使ったマッチャの組み合わせ

ファイル名が「output_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `output`" do
specify "you can pass a matcher in place of the output (to_stdout)" do
expect {
print 'foo'
}.to output(a_string_starting_with('f')).to_stdout
end
specify "you can pass a matcher in place of the output (to_stderr)" do
expect {
warn 'foo'
}.to output(a_string_starting_with('f')).to_stderr
end
end

rspec output_spec.rbを実行した場合、

全ての例がパスするはずです。

raise_errorを使ったマッチャの組み合わせ

ファイル名が「raise_error_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `raise_error`" do
specify "you can pass a matcher in place of the message" do
expect {
raise RuntimeError, "this goes boom"
}.to raise_error(RuntimeError, a_string_ending_with("boom"))
end
end

rspec raise_error_spec.rbを実行した場合、

全ての例がパスするはずです。

start_withを使ったマッチャの組み合わせ

ファイル名が「start_with_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `start_with`" do
specify "you can pass matchers in place of exact values" do
expect(["barn", "food", 2.45]).to start_with(
a_string_matching("bar"),
a_string_matching("foo")
)
end
end

rspec start_with_spec.rbを実行した場合、

全ての例がパスするはずです。

throw_symbolを使ったマッチャの組み合わせ

ファイル名が「throw_symbol_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `throw_symbol`" do
specify "you can pass a matcher in place of a throw arg" do
expect {
throw :pi, Math::PI
}.to throw_symbol(:pi, a_value_within(0.01).of(3.14))
end
end

rspec throw_symbol_spec.rbを実行した場合、

全ての例がパスするはずです。

yield_with_argsを使ったマッチャの組み合わせ

ファイル名が「yield_with_args_spec.rb」であるファイルが以下の内容であるとき:

RSpec.describe "Passing matchers to `yield_with_args`" do
specify "you can pass matchers in place of the args" do
expect { |probe|
"food".tap(&probe)
}.to yield_with_args(a_string_matching(/foo/))
end
end

rspec yield_with_args_spec.rbを実行した場合、

全ての例がパスするはずです。

yield_successive_argsを使ったマッチャの組み立て

次の内容で「yield_successive_args_spec.rb」という名前のファイルを作成します。

RSpec.describe "Passing matchers to `yield_successive_args`" do
specify "you can pass matchers in place of the args" do
expect { |probe|
[1, 2, 3].each(&probe)
}.to yield_successive_args(a_value < 2, 2, a_value > 2)
end
end

rspec yield_successive_args_spec.rbを実行すると、

全ての例がパスするはずです。

複合的なand式を使ったマッチャの組み立て

次の内容で「include_spec.rb」という名前のファイルを作成します。

RSpec.describe "Passing a compound matcher expression to `include`" do
example do
expect(["food", "drink"]).to include( a_string_starting_with("f").and ending_with("d"))
end
end

rspec include_spec.rbを実行すると、

全ての例がパスするはずです。