LoginSignup
52
40

More than 5 years have passed since last update.

RSpec - expectの中を汚さずに複雑な検証ができるsatisfyマッチャがすごい

Last updated at Posted at 2015-02-13

やりたいこと

配列の中に数値が格納されていて、数値の桁数が全て8桁であることを検証したい。というケースがありました。

allマッチャ

allというマッチャで、配列の要素全てに対してマッチャを適用できるのですが、「数値の桁数が◯桁であること」を検証してくれるマッチャはないので、自分でなんとかしないといけませんでした。

mapで変換してから検証する

mapメソッドを使って、数値の配列を桁数の配列に変換し、allマッチャに渡す方法。

xxx_spec.rb
it { expect(nums.map{|num|num.abs.to_s.size}).to all(eq 8) }

うーん…
なんだか気持ち悪い

ループで回してしまう

xxx_spec.rb
it '全ての数が8桁であること' do
  nums.each do |num|
    expect(num.abs.to_s.size).to eq 8
  end
end

うーん…
大して変わらない

気持ち悪さの原因

どちらもexpectに渡すのが、検証したい対象を変換したもの になっているのが気持ち悪さの原因のような気がします。

expectには数値を渡して、マッチャが「マイナスを取って文字列にしたら長さが8であること」を検証してくれたらいいのになあ。と思っていました。

satisfyマッチャ

satisfyというマッチャを見つけました。これはブロックを受け取って、そのブロックがtrueを返すことを検証してくれます。
辞書を引いてみると、(人を)満足させるとか(要件を)満たすという意味らしいです。
これを使えば気持ち悪くない書き方ができそうです。

xxx_spec.rb
it { expect(nums).to all(satisfy {|num| num.abs.to_s.size == 8 } ) }

ちょっと自然な感じになりました。
ただ、カッコが多くて見づらいのでブロックを分けます。

xxx_spec.rb
be_8_digits = -> num { num.abs.to_s.size == 8 }
it { expect(nums).to all(satisfy &be_8_digits) }

スッキリしました。

expectの中が、検証すべき対象になったので、subjectでまとめてis_expected.toすることもできます。

まとめ

  • expectの中には、テスト対象そのものを入れたい
  • マッチャのために変換したものを入れると、意味が分かりづらくなる
  • satisfyマッチャを使うとブロックを使って柔軟な検証ができる!
  • expectの中が汚れないので気持ちが良い
52
40
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
40