はじめに
私はRailsを最近学びだして実際に簡単な業務からさせていただいている初心者です。
チュートリアルレベルの学んだことから、よりスキルアップするため
実際に動いているサービスのコードを触って気づいたことをまとめたいと思います。
あくまでまだまだ初心者である自分自身の理解を高めるためのアウトプットですので
間違いや勘違い等あればご指摘いただけますと幸いです。
また少しでも同じようなレベルの方の助けになればと思います。
ネストしがちなRSpecの可読性を高める
タイトル通りですが、(自分にとって)複雑なモデルやメソッドのRSpecを記述している際、どうしてもネストが深くなりすぎることがありました。
特に条件ごとに検証する際のdescribe
やcontext
あたりが多くなるとどんどん見づらくなって仕方ないので自分なりにまとめてみました。
同じ結果を条件ごとに検証するならsubjectにまとめる
例えばこのような、商品のnameが仮に10文字でバリデーションをかけている場合だとかは
described 'product is valid?' do
context '0文字の場合' do
let(:product) { FactoryBot.create(:product, name: 'a' * 0)
it { is_expected.to be_invalid }
end
context '9文字の場合' do
let(:product) { FactoryBot.create(:product, name: 'a' * 9)
it { is_expected.to be_invalid }
end
context '10文字の場合'do
let(:product) { FactoryBot.create(:product, name: 'a' * 10)
it { is_expected.to be_valid }
end
end
のようにすべてのケースでproductを作成していくよりも、
結局検証したい結論(≒subject)はproductが保存できるかどうかなので
described 'product is valid?' do
subject(:product) { FactoryBot.create(:product, name: name) }
context '0文字の場合' do
let(:name) { '' }
it { is_expected.to be_invalid }
end
context '9文字の場合' do
let(:name) { 'a' * 9 }
it { is_expected.to be_invalid }
end
context '10文字の場合'do
let(:name) { 'a' * 10 }
it { is_expected.to be_valid }
end
end
のようにsubject
で事前に共通の処理を定義して、context
ごとに条件を分けたい部分を渡していく方が見た目的にもスッキリする。
使い回す結果はshared_examplesにまとめて呼び出す
また上記のコードの中の
it { is_expected.to be_valid }
it { is_expected.to be_invalid }
これら含め、例えば
it { is_expected.to eq 200 }
だとか、正しくレスポンスを受けられているか等の結果は何かと使い回すことが多いので、そういった結果はshared_examples
にまとめて、it_behaves_like
で呼び出すと1つ1つのテストコード内での期待する結果がわかりやすい。
さっきのをさらに修正すると
described 'product is valid?' do
subject(:product) { FactoryBot.create(:product, name: name) }
shared_examples '商品は保存できる' do
it { is_expected.to be_valid }
end
shared_examples '商品は保存できない' do
it { is_expected.to be_invalid }
end
context '0文字の場合' do
let(:name) { '' }
it_behaves_like '商品は保存できない'
end
context '9文字の場合' do
let(:name) { 'a' * 9 }
it_behaves_like '商品は保存できない'
end
context '10文字の場合'do
let(:name) { 'a' * 10 }
it_behaves_like '商品は保存できる'
end
end
のように1つ1つのcontext
内での条件と結果がわかりやすくなる。
今回は簡単なテストなのでこれだけですが、shared_examples
内でもう少し検証が増える場合は
shared_examples '商品は保存できる' do
it '商品の持つ情報は妥当である' do
is_expected.to be_valid
end
it '商品の名前がhoge' do
is_expected.to hoge
end
end
shared_examples '商品は保存できない' do
it '商品の持つ情報は妥当ではない' do
is_expected.to be_invalid
end
it '商品の名前がhoge' do
is_expected.to hoge
end
end
のようにshared_examples
内の検証にも文章入れた状態で呼び出せば、
shared_examples
の中のどの検証で落ちているのかエラーメッセージから読み取りやすくなる。
全体的に文章とかはざっくりアテているので適宜適切な文章に修正してください。
大体今気をつけていることはこの辺りかな、と思います。
手元でさっと検証できないので頭に入っていることを書き出したのですが間違い等あればご指摘ください。
またコントローラのrequest specとかでクエリパラメータが正しく渡っているか/渡っていないかのような検証時にも
今回のような条件分けをするとスッキリ見やすくて良かったです。
テストコードが綺麗になるだけでテストコードを書くモチベーションがかなり上がったのと、エラーを拾いやすくなったのでぜひ。