🎉

rspec-parameterized でRSpecをDRYに書く

2021/06/13に公開

こんにちは。

Railsのテスティングフレームワークでは、よくRSpecが採用されているかと思います。

日々業務でテストを書いていると、

  • 同じようなテストを書いているけど、もっとDRYに書きたい
  • 入力値だけが異なるテストを何回も書いている

と、ふと思います。

そんなときに助けてくれるのが、rspec-parameterizedです。

Parameterized Test って?

テストへのパラメータを様々な方法で提供することで、異なるパラメータのテストを簡素に記述することができるテスト手法です。
調べるとJUnit の例がよく出てきますね。

RSpecでは、本体で Parameterized Test がサポートされていないので、rspec-parameterized gem を使って拡張してあげる必要があります。

使ってみる

まずはいつものやつ

Gemfile
gem 'rspec-parameterized'
bundle install

# or
gem install rspec-parameterized

書き方はREADMEを見ていきます。

# Nested Array Style
describe "plus" do
  # where でパラメータを宣言します
  # パターン1: a=1, b=2, answer=3
  # パターン2: a=5, b=8, answer=13
  # パターン3: a=0, b=0, answer=0
  where(:a, :b, :answer) do
    [
      [1 , 2 , 3],
      [5 , 8 , 13],
      [0 , 0 , 0]
    ]
  end

  # テストを with_them のブロックで囲みます
  with_them do
    it "should do additions" do
      expect(a + b).to eq answer
    end
  end

  with_them do
    # with_them ブロック内であれば、params メソッドでパラメータを確認できます
    # with_them ブロック内であれば、all_params メソッドですべてのパラメータを確認できます
    it "#{params[:a]} + #{params[:b]} == #{params[:answer]}" do
      expect(a + b).to eq answer
    end
  end
end

where でパラメータを宣言し、テストを with_them で囲むだけで、
パラメータで宣言したケース分だけテストが実行されます。便利ですね。

パラメータの書き方色々

# Table Syntax Style
using RSpec::Parameterized::TableSyntax

where(:a, :b, :answer) do
  1 | 2 | 3
  5 | 8 | 13
  0 | 0 | 0
end

# Hash and Array Style
where(a: [1, 3], b: [5, 7, 9], c: [2, 4])
# このように記述すると、それぞれの値の組み合わせ分テストが実行されます
# [
#   [1, 5, 2],
#   [1, 5, 4],
#   [1, 7, 2],
#   [1, 7, 4],
#   [1, 9, 2],
#   [1, 9, 4],
#   [3, 5, 2],
#   [3, 5, 4],
#   [3, 7, 2],
#   [3, 7, 4],
#   [3, 9, 2],
#   [3, 9, 4]
# ]

# Verbose Syntax
# これは明示的にパラメータの意図を書きたいときに便利
where do
  {
    "positive integers" => {
      a: 1,
      b: 2,
      answer: 3,
    },
    "negative_integers" => {
      a: -1,
      b: -2,
      answer: -3,
    },
    "mixed_integers" => {
      a: 3,
      b: -3,
      answer: 0,
    },
  }
end

# ↑の書き方は case_name を使って、書くこともできる
describe "Custom names for regular syntax" do
  where(:case_name, :a, :b, :answer) do
    [
      ["positive integers",  6,  2,  8],
      ["negative integers", -1, -2, -3],
      [   "mixed integers", -5,  3, -2],
    ]
  end

  with_them do
    it "should do additions" do
      expect(a + b).to eq answer
    end
  end
end
# Output:
# Custom names for regular syntax
#   positive integers
#     should do additions
#   negative integers
#     should do additions
#   mixed integers
#     should do additions

以上です
RSpecもDRYに見通しよく書きたい!

Discussion