プレディケートマッチャー
Rubyオブジェクトは一般的にプレディケートメソッドを提供します。
(7.zero? # => false
0.zero? # => true
[1].empty? # => false
[].empty? # => true
{ :a => 5 }.has_key?(:b) # => false
{ :b => 5 }.has_key?(:b) # => true
これらに対して期待値を設定するために、基本的な等価マッチャーを使用することができます。
expect(7.zero?).to eq true # "expected true, got false (using ==)" というエラーが発生します
...しかし、RSpecはより読みやすく、より良いエラーメッセージを提供する動的なプレディケートマッチャーを提供しています。
任意のプレディケートメソッドに対して、RSpecは対応するマッチャーを提供します。単純にメソッドの前に be_
を付け、疑問符を削除します。例:
expect(7).not_to be_zero # 7.zero? を呼び出します
expect([]).to be_empty # [].empty? を呼び出します
expect(x).to be_multiple_of(3) # x.multiple_of?(3) を呼び出します
また、has_
で始まるプレディケートメソッド(例: Hash#has_key?
)に対しては、be_has_key
という形式は意味をなさないため、別の形式を使用することができます。
expect(hash).to have_key(:foo) # hash.has_key?(:foo) を呼び出します
expect(array).not_to have_odd_values # array.has_odd_values? を呼び出します
いずれの場合も、RSpecはわかりやすく明確なエラーメッセージを提供します。例えば:
expected zero? to be truthy, got false
プライベートメソッドを呼び出す場合も失敗します:
expected private_method? to return true but it's a private method
マッチャーに渡された引数は、プレディケートメソッドにも渡されます。
subject
が be_zero
(Integer#zero?に基づく)であることを期待する
次の内容で "should_be_zero_spec.rb" という名前のファイルがあるとします:
RSpec.describe 0 do
it { is_expected.to be_zero }
end
RSpec.describe 7 do
it { is_expected.to be_zero } # deliberate failure
end
rspec should_be_zero_spec.rb
を実行すると
出力に "2 examples, 1 failure" が含まれること
かつ、出力に "expected 7.zero?
to be truthy, got false" が含まれること
subject
が be_empty
ではないことを期待する(Array#empty?に基づく)
次の内容で "should_not_be_empty_spec.rb" という名前のファイルがあるとします:
RSpec.describe [1, 2, 3] do
it { is_expected.not_to be_empty }
end
RSpec.describe [] do
it { is_expected.not_to be_empty } # deliberate failure
end
rspec should_not_be_empty_spec.rb
を実行すると
出力に "2 examples, 1 failure" が含まれること
かつ、出力に "expected [].empty?
to be falsey, got true" が含まれること
subject
がhave_key
を持つことを期待する(Hash#has_key?に基づく)
「should_have_key_spec.rb」という名前のファイルがあるときに、
RSpec.describe Hash do
subject { { :foo => 7 } }
it { is_expected.to have_key(:foo) }
it { is_expected.to have_key(:bar) } # deliberate failure
end
を実行すると、
rspec should_have_key_spec.rb
を実行すると、
出力には「2つの例、1つの失敗」という文字列が含まれているはずです。
また、出力には「{:foo=>7}.has_key?(:bar)
が真であることを期待しましたが、偽でした」という文字列が含まれているはずです。
subject
がすべての小数を持つことを期待する(カスタムのhas_decimals?
メソッドに基づく)
「should_not_have_all_string_keys_spec.rb」という名前のファイルがあるときに、
class Float
def has_decimals?
round != self
end
end
RSpec.describe Float do
context 'with decimals' do
subject { 4.2 }
it { is_expected.to have_decimals }
end
context 'with no decimals' do
subject { 42.0 }
it { is_expected.to have_decimals } # deliberate failure
end
end
を実行すると、
rspec should_not_have_all_string_keys_spec.rb
を実行すると、
出力には「2つの例、1つの失敗」という文字列が含まれているはずです。
また、出力には「42.0.has_decimals?
が真であることを期待しましたが、偽でした」という文字列が含まれているはずです。
マッチャーの引数は述語メソッドに渡されます
「predicate_matcher_argument_spec.rb」という名前のファイルがあるときに、
class Integer
def multiple_of?(x)
(self % x).zero?
end
end
RSpec.describe 12 do
it { is_expected.to be_multiple_of(3) }
it { is_expected.not_to be_multiple_of(7) }
# deliberate failures
it { is_expected.not_to be_multiple_of(4) }
it { is_expected.to be_multiple_of(5) }
end
を実行すると、
rspec predicate_matcher_argument_spec.rb
を実行すると、
出力には「4つの例、2つの失敗」という文字列が含まれているはずです。
また、出力には「12.multiple_of?(4)
が偽であることを期待しましたが、真でした」とい う文字列が含まれているはずです。
さらに、出力には「12.multiple_of?(5)
が真であることを期待しましたが、偽でした」という文字列が含まれているはずです。
strict_predicate_matchers
設定はtrue
とfalse
以外の結果のマッチングに影響を与えます
「strict_or_not.rb」という名前のファイルがあるときに、
class StrangeResult
def has_strange_result?
42
end
end
RSpec.describe StrangeResult do
subject { StrangeResult.new }
before do
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.strict_predicate_matchers = strict
end
end
end
context 'with non-strict matchers (default)' do
let(:strict) { false }
it { is_expected.to have_strange_result }
end
context 'with strict matchers' do
let(:strict) { true }
# deliberate failure
it { is_expected.to have_strange_result }
end
end
を実行すると、
rspec strict_or_not.rb
を実行すると、
出力には「2つの例、1つの失敗」という文字列が含まれているはずです。
また、出力には「has_strange_result?
が真を返すことを期待しましたが、42でした」という文字列が含まれているはずです。
be_predicate
でプライベートメソッドを呼び出すとエラーが発生します
「attempting_to_match_private_method_spec.rb」という名前のファイルがあるときに、
class WithPrivateMethods
def secret?
true
end
private :secret?
end
RSpec.describe 'private methods' do
subject { WithPrivateMethods.new }
# deliberate failure
it { is_expected.to be_secret }
end
を実行すると、
rspec attempting_to_match_private_method_spec.rb
を実行すると、
出力には「1つの例、1つの失敗」という文字列が含まれているはずです。
また、出力には「secret?
はプライベートメソッドです」という文字列が含まれているはずです。
have_predicate
でプライベートメソッドを呼び出すとエラーが発生します
「attempting_to_match_private_method_spec.rb」という名前のファイルがあるときに、
class WithPrivateMethods
def has_secret?
true
end
private :has_secret?
end
RSpec.describe 'private methods' do
subject { WithPrivateMethods.new }
# deliberate failure
it { is_expected.to have_secret }
end
実行するとき rspec attempting_to_match_private_method_spec.rb
を実行します。
その結果 出力に "1 example, 1 failure" が含まれている必要があります。
かつ 出力に "has_secret?
はプライベートメソッドです" が含まれている必要があります。