テストの書き方における疑問点(メモ)
テストの書き方で疑問だった箇所とその理由
describe '検索機能' do let(:article_with_author) { create(:article, :with_author, author_name: '田中') } let(:article_with_another_author) { create(:article, :with_author, author_name: '佐藤') } # 中略 it '著者名で絞り込み検索ができること' do article_with_author # ① article_with_another_author visit admin_articles_path select '田中', from: 'q[author_id]' #② click_button '検索' expect(page).to have_content(article_with_author.title), '著者名での検索ができていません' expect(page).not_to have_content(article_with_another_author.title), '著者名での絞り込みができていません' end
- 指定した著者名で検索ができているのかテストしたいので、著者名田中の記事と著者名佐藤の記事をそれぞれletで作成している
① article_with_authorと記載する理由は?
describe直下に記載したletをlet!にしてしまえば、わざわざitの下にarticle_with_author
,article_with_another_author
と記載しなくても済むのに、なぜ上記のようにしているのか。
- 結論let!でも構わない
- 全部let!って良いじゃんと思っていたけれど、let!でexampleを個別実行した場合、そのテストケースに必要ないデータまで作成されてしまいテスト実行時間が若干遅くなる
- 今は関係なくてもアプリの拡大があれば、パフォーマンスも考慮しなくてはならないので頭の片隅に入れておく
- ただテストにおいて最も重視されるべきなのは、コードの記述量でも実行時間でもなく「可読性」!!
Clean Test Code Revised - Speaker Deck
② select '田中', from: 'q[author_id]'の箇所
Capybaraにおけるシミュレーションでselect '田中', from: 'q[author_name]'
と記載すべきなのか。(select article_with_author.author_name
と書いた方が今までの学習に近い)
E2E(システムスペックのようなユーザーの操作をシミュレーションする)テストにおいて、「ユーザーの操作を忠実に再現すべき」という考えがあり、その点で言えば
fill_in name, with: '田中'
の方が好ましいのではないかという考え方
→これに関しては書き手の考え方によるので、厳格にこうしなければならない!!というものはない。あとは単純に、何を選択するのか、入力するのか明記してあった方がリーダブルである
→確かに圧倒的にaritcle_with_author.author_nameみたいに長々書くより読みやすいと思った。
FactoryBotにおけるcreateとbuildの使い所
trait :with_tag do transient do sequence(:name, "test_tag_name_1") sequence(:slug, "test_tag_slug_1") end after(:build) do |article, evaluator| article.tags << build(:tag, name: evaluator.tag_name, slug: evaluator.tag_slug) # ここ end end trait :with_sentence do transient do sequence(:sentence_body, 'test_body_1') end after(:build) do |article, evaluator| article.sentences << create(:sentence, body: evaluator.sentence_body) # ここ end end
コールバックのブロック内、シャープの箇所でbuildとcreateと追加分けている理由は?
article_blockモデルのバリデーションをチェック
# app/models/aritcle_block.rb class ArticleBlock < ApplicationRecord belongs_to :article belongs_to :blockable, polymorphic: true, dependent: :destroy # ここ with_options on: %i[create update] do validates :blockable_type, presence: true validates :blockable_id, presence: true #これ validates :level, presence: true, uniqueness: { scope: :article_id } end
belongs_to :blockable, polymorphic: true, dependent: :destroy
の記述があるので、blockable_typeとblockable_idのバリデーションは要らない可能性アリ- 悪さ(?)をしているのは
validates :blockable_id, presence: true
の一行らしい - blockable_idはDB保存時に自動で振られる値のため、DBに保存しないbuildではnilになり、バリデーションに引っ掛かってしまう。このため、createを用いてテストに通るようにする
参考サイト
Rails tips: RSpecテストの高速化/リファクタリングに役立つ4つの手法(翻訳)|TechRacho by BPS株式会社