rspec-parameterized ことはじめ

### rspec-parameterizedとは
簡単なパラメータ化したデータのテスト(parameterized test)を書けるようにするgemです。
https://github.com/tomykaira/rspec-parameterized

### 事前準備
いつものようにGemfileに書いて`bundle install`します。

```ruby:Gemfile
group :test do
  gem 'rspec-parameterized'
end
```

### 比較のために、FizzBuzzを例にして、普通のspecを書く

```ruby:calculator.rb
module Calculator
  def self.fizzbuzz(num)
    if num % 15 == 0
      "FizzBuzz"
    elsif num % 3 == 0
      "Fizz"
    elsif num % 5 == 0
      "Buzz"
    else
      num
    end
  end
end
```

```ruby:calculator_spec.rb
require 'rails_helper'

RSpec.describe Calculator do
  describe "fizzbuzz" do
    subject { Calculator.fizzbuzz(num) }

    context "when number is 1" do
      let(:num) { 1 }
      it { expect(subject).to eq 1 }
    end

    context "when number is 2" do
      let(:num) { 2 }
      it { expect(subject).to eq 2 }
    end

    context "when number is 3" do
      let(:num) { 3 }
      it { expect(subject).to eq "Fizz" }
    end

    context "when number is 4" do
      let(:num) { 4 }
      it { expect(subject).to eq 4 }
    end

    context "when number is 5" do
      let(:num) { 5 }
      it { expect(subject).to eq "Buzz" }
    end

    # 6..14 examples

    context "when number is 15" do
      let(:num) { 15 }
      it { expect(subject).to eq "FizzBuzz" }
    end
  end
end
```

上記specを、rspec-parameterizedを使ってリファクタリングします。

####Nested Array Style

実際に、rspec-parameterizedを用いるとこのようになります。

```ruby:calculator_spec.rb
require 'rails_helper'

RSpec.describe Calculator do
  describe "fizzbuzz" do
    subject { Calculator.fizzbuzz(num) }

    where(:num, :answer) do
      [
        [1, 1],
        [2, 2],
        [3, "Fizz"],
        [4, 4],
        [5, "Buzz"],
        # 6..14 examples
        [15, "FizzBuzz"]
      ]
    end

    with_them do
      it { expect(subject).to eq answer }
    end
  end
end
```

他にも、いくつか書き方があります。


#### Hash and Array Style

このとき、
[a, b]は
[1, 5],[1, 7],[1, 9]
[3, 5],[3, 7],[3, 9]
[5, 5],[5, 7],[5, 9]
の9パターンが実行されます。
(FizzBuzzだと良い例が書けませんでした...)

```ruby
describe "Hash arguments" do
  where(a: [1, 3, 5], b: [5, 7, 9])

  with_them do
    it { expect(a + b).to be_even }
  end
end
```


#### Table Syntax Style (like Groovy spock)

・Ruby2.1以降である必要があります。
・`using RSpec::Parameterized::TableSyntax`を書く必要があります。

```ruby
using RSpec::Parameterized::TableSyntax
describe "fizzbuzz" do
  subject { Calculator.fizzbuzz(num) }

  where(:num, :answer) do
    1 | 1 
    2 | 2
    3 | "Fizz"
    4 | 4
    5 | "Buzz"
    # 6..14 examples
    15 | "FizzBuzz"
  end

  with_them do
    it { expect(subject).to eq answer }
  end
end
```

#### Verbose Syntax

```ruby
describe "fizzbuzz" do
  subject { Calculator.fizzbuzz(num) }

  where do
    {
      "multiple of 3" => { num: 3, answer: "Fizz" },
      "multiple of 5" => { num: 5, answer: "Buzz" },
      "multiple of 15" => { num: 15, answer: "FizzBuzz" },
      "not multiple of 3 and 5" => { num: 16, answer: 16 }
    }
  end

  with_them do
    it { expect(subject).to eq answer }
  end
end
```

#### lambda parameter
```ruby
describe "fizzbuzz" do
  subject { Calculator.fizzbuzz(num) }

  where(:num, :answer) do
    [
      [1, -> {should == 1}],
      [2, -> {should == 2}],
      [3, -> {should == "Fizz"}],
      [4, -> {should == 4}],
      [5, -> {should == "Buzz"}],
      # 6..14 examples
      [15, -> {should == "FizzBuzz"}]
    ]
  end

  with_them do
    subject { Calculator.fizzbuzz(num) }
    it { self.instance_exec(&answer) }
  end
end
```

#### テストをpendingにしたい時
従来の記法の通り、xit使えばOKです。

```ruby
with_them do
  xit { expect(subject).to eq answer }
end
```

#### 実際のビジネスロジックに適用させるとどうなるか
こうなりました。
[rspec-parameterizedを使って、RSpecをリファクタリングした話](https://qiita.com/shota_yamashita/items/ceb68a188b5471e2c7a5)