n350071のブログ

主にRubyなフリーランスエンジニア

RSpecのFeatureテストでshared_exampleみたいなことをする

2019-08-24 n350071RSpec

🤔 状況: 同じ内容が多く、true/falseの判断が分かりづらい

この例では1つの要素をクリックした場合だけをテストしていますが、これをコピペして何通りものテストを書くと考えると、書き間違いや、読んでもよく理解できないコードになりそうです。

scenario 'それぞれのパネルが開いたり閉じたりすること' do
  visit hoge_path(hoge_params)
  within('div.section-fugas') do
    expect(find('div.section-fuga:nth-child(1)')).to have_selector('div.section-fuga-body')
    expect(find('div.section-fuga:nth-child(2)')).to have_selector('div.section-fuga-body')
    expect(find('div.section-fuga:nth-child(3)')).not_to have_selector('div.section-fuga-body')
    expect(find('div.section-fuga:nth-child(4)')).not_to have_selector('div.section-fuga-body')          
    find('div.section-fuga:nth-child(1)').find('a.section-fuga-a').click
    expect(find('div.section-fuga:nth-child(1)')).not_to have_selector('div.section-fuga-body')
    expect(find('div.section-fuga:nth-child(2)')).to have_selector('div.section-fuga-body')
    expect(find('div.section-fuga:nth-child(3)')).not_to have_selector('div.section-fuga-body')
    expect(find('div.section-fuga:nth-child(4)')).not_to have_selector('div.section-fuga-body')          
  end
end

👍 POROで解決!ふつうにdefを使う

ふつうにメソッドに切り出します。 さらに、matcherを変化できるようにsend(method, args)を引数と組み合わせて使うことで、柔軟性が高まります。 結果、テスト本体では、見える/見えない(true/false)に集中できるようになりました。

def visibility_test(visibilities)
  expect(find('div.section-fuga:nth-child(1)')).send(visibilities[0] ? :to : :not_to, have_selector('div.section-fuga-body'))
  expect(find('div.section-fuga:nth-child(2)')).send(visibilities[1] ? :to : :not_to, have_selector('div.section-fuga-body'))
  expect(find('div.section-fuga:nth-child(3)')).send(visibilities[2] ? :to : :not_to, have_selector('div.section-fuga-body'))
  expect(find('div.section-fuga:nth-child(4)')).send(visibilities[3] ? :to : :not_to, have_selector('div.section-fuga-body'))
end
scenario 'それぞれのパネルが開いたり閉じたりすること' do
  visit hoge_path(hoge_params)
  within('div.section-fugas') do
    visibility_test([true,true,false,false])
    find('div.section-fuga:nth-child(1)').find('a.section-fuga-a').click
    visibility_test([false,true,false,false])
  end
end

👌 展望

さきほどのコードを完成させてみましょう。
4箇所クリックしてパネルが独立に開閉する ということが読み取りやすくなったでしょうか。

scenario 'それぞれのパネルが開いたり閉じたりすること' do
  visit hoge_path(hoge_params)
  within('div.section-fugas') do
    visibility_test([true,true,false,false])
    find('div.section-fuga:nth-child(1)').find('a.section-fuga-a').click
    visibility_test([false,true,false,false])
    find('div.section-fuga:nth-child(2)').find('a.section-fuga-a').click
    visibility_test([false,false,false,false])
    find('div.section-fuga:nth-child(3)').find('a.section-fuga-a').click
    visibility_test([false,false,true,false])
    find('div.section-fuga:nth-child(4)').find('a.section-fuga-a').click
    visibility_test([false,false,true,true])
  end
end