LoginSignup
0
0

More than 5 years have passed since last update.

rspecで複数のexpectをまとめて使い回す。

Posted at

概要

rspecでテストを書いていると、値だけ違う同じexpectの組み合わせを何度も行うことが多いと思います。仕様が変わったりすると大量に変更箇所が出てきて、「あ〜やっぱりテストはコストがかかるからやめようか〜」なんてことになりかねません。ヘルパーメソッド的なものにまとめたいと思いました。

で、どこにexpectをまとめたヘルパーメソッドを作るのか探してみると、カスタムマッチャーを使った例がいくつか見つかりました。

ところがカスタムマッチャーのmatchメソッドはtrue/falseを返すように設計されているため、なかでexpectを使うとエラーメッセージがもみ消されて、どこで、どんな感じにテストがこけたのか全く分からなくなってしまいます。

また、追加的なテストはchainメソッドで行いますが、これはテストを実行するというより、メンバー変数に値を入れておき、matchメソッドの中でその変数の有無を見て追加チェックを行うためロジックが複雑になってしまいます。

そこで、いい感じにテストをまとめられるmoduleを作りましたので共有させていただきます。エラーメッセージの問題はこちらの投稿を参考にしました。

モジュールはgistに公開しました。
https://gist.github.com/gomo/83e021828a0aeade3b3370d404c2ee7b

使い方

RSpec::Matchers.defineのブロックにincludeして使います。

RSpec::Matchers.define :have_foo_bar do |foo, bar|
  include ChainChecker

エントリーポイントはmatchではなくmainに渡すブロックになります。

RSpec::Matchers.define :have_foo_bar do |foo, bar|
  include ChainChecker

  main do |actual|
    expect(actual.foo).to eq foo
    expect(actual.bar).to eq bar
    # メンバー変数に入れて置くとchainの中で利用可能です。
    @quux = actual.quux
  end

chainメソッドではcheckメソッドにブロックを渡してテストを予約します。これでmainに渡したブロックが最初に評価され、その後chainを呼び出した順にcheckブロックが評価されていきます。

RSpec::Matchers.define :have_foo_bar do |foo, bar|
  include ChainChecker

  main do |actual|
    expect(actual.foo).to eq foo
    expect(actual.bar).to eq bar
    @quux = actual.quux
  end

  chain :with_quux do |baz, qux|
    check do |actual|
      expect(@quux.baz).to eq baz
      expect(@quux.qux).to eq qux
    end
  end
end

テストコードは下記のようになります。

context 'some' do
  it 'should have foo and bar' do
    some = Some.find(1)
    expect(some).to have_foo_bar('foo value', 'bar value')
      .with_quux('baz value', 'qux value')
  end
end
0
0
0

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
0
0