@ledsun blog

Hのキーがhellで、Sのキーがslaveだ、と彼は思った。そしてYのキーがyouだ。

DRYな気持ちでRSpecでFizzBuzzのテストコードを書くと?

素直な気持ちで書くとexpect(fizzbuzz 1).to eq '1'に似た文がたくさん出てきます。 DRYにしたくなったので、テストデータをテーブルで定義してグルグルっとアサーションを回します。

require './fizzbuzz'

describe 'FizzBuzz' do
  it do
    [
      [0, ''],
      [1, '1'],
      [2, '2'],
      [3, 'FIZZ'],
      [4, '4'],
      [5, 'BUZZ'],
      [6, 'FIZZ'],
      [7, '7'],
      [8, '8'],
      [9, 'FIZZ'],
      [10, 'BUZZ'],
      [11, '11'],
      [12, 'FIZZ'],
      [13, '13'],
      [14, '14'],
      [15, 'FIZZBUZZ'],
      [16, '16'],
      [100, 'BUZZ'],
      [101, '']
    ].each do | number, answer |
      expect(fizzbuzz number).to eq answer
    end
  end
end

Parameterized Test at XUnitPatterns.comによると、こういうのをTabular Test(表形式テスト)と言うそうです。 素直に書くよりは簡潔になりました。 一つのitの中で評価するので、途中の一つのテストケースが失敗すると後続のテストケースが実行されません。

と、思うじゃん? RSpecの場合、テストケースを定義するタイミングと、テストランナーが定義されたテストケースを集めるタイミングがわかれていないので、次のように書けます。

require './fizzbuzz'

describe 'FizzBuzz' do
  [
    [0, ''],
    [1, '1'],
    [2, '2'],
    [3, 'FIZZ'],
    [4, '4'],
    [5, 'BUZZ'],
    [6, 'FIZZ'],
    [7, '7'],
    [8, '8'],
    [9, 'FIZZ'],
    [10, 'BUZZ'],
    [11, '11'],
    [12, 'FIZZ'],
    [13, '13'],
    [14, '14'],
    [15, 'FIZZBUZZ'],
    [16, '16'],
    [100, 'BUZZ'],
    [101, '']
  ].each do | number, answer |
    it { expect(fizzbuzz number).to eq answer }
  end
end

パラメータ毎にitが実行されるので、途中のテストケースが失敗しても、後続のテストケースは実行されます。 RSpecだけでもパラメタライズドテストは書けます。