Rails Diary

プログラミングの学習記録です。

RSpec作成の流れ

RSpecの作り方の流れをまとめておきたい。
※ 過去のメモと重複箇所多

テストコードはプロダクトコードに比べると絶対的な正解というのがあまりなく、色々な書き方が存在するので、解答例と寸分狂わずみたいなことを目指さなくて良い。

RSpec

スペックファイル作成

bundle exec rails g rspec:system AdminArticlePreviews

ドライバ設定, supportファイルの読み込み設定

① スペックファイルごとにドライバの初期設定が記載されているが、共通項目として別のsupportディレクトリ配下にドライバの設定ファイルを作成する
# spec/support/capybara.rb
RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selnium, using: :headless_chrome, screen_size: [1920, 1080]
  end
end
  • ドライバとはテストにおける動作システム。テストの実行環境のこと。デフォルトで設定されているRack::Testは高速だが、JSをテストすることができないので、JSが使えるseleniumドライバを設定している
  • 互換性の問題でヘッドレスブラウザ(テストで使うGUIを持たないブラウザ)にはChromeを採用した方が良いらしい。Chromeを使うためにはwebdriversジェムを追加する。そうすると、依存関係にあるselenium-webdriverも一緒にインストールしてくれるので明示的に書かなくていいとのこと。(詳しくはよくわからない)
② 各スペックがsupport配下のファイル設定を読み込むよう、rails_helper.rbに記載
# 元々コメントアウトになっているものを外せばOK
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

FactoryBotでテストデータを作成

① FactoryBotのファイルを作成
$ bundle exec rails g factory_bot:model user
② テストデータを作成する
FactoryBot.define do
  factory :user do
    sequence(:name, "general_1" } 
    password { "password" }
    password_confirmation { "password" }
    role { :general }

    trait :admin do
      sequence(:name, "admin_1")
      role { :admin }
    end
  end
end
  • sequenceで連番データの作成ができる
  • ユニークなテストデータを作りたい時に使う
  • sequenceはブロックを渡さずに第二引数を渡すとRubyの.nextメソッドが呼び出され、上記のような書き方でも連番が作れる。sequence(:email) { |n| "test#{n}@example.com" }のように連続させたい数字が真ん中に挟まっている場合、.nextが上手く反映されないので大人しくブロックを渡す
  • 管理者権限はtraitを用いて付与
③ FactoryBotの記載省略を設定ファイルに追加

通常、FactoryBot.create(:user)のような記載でダミーデータを作成するが、設定ファイルに下記の記載をすることで先頭のFactoryBotを省略できる

# spec/rails_helper.rb
confin.include FactoryBot::Syntax::Methods

user = create(:user)ないし、let(:user) { create(:user) }みたいな形で作成できる。

ログイン処理を共通項目として切り分ける

ログイン後のテストにおいて、一々ログイン処理をテストに書き込むのはDRYさに欠ける。このため、ログイン処理をモジュールに切り分ける。

① support配下にログイン処理を作成

# spec/support/login_macros.rb
module LoginMacros
  def login_as(user)
    visit admin_login_identifier_path
    click_link 'Login'
    fill_in 'Email', with: user.email
    fill_in 'Password', with: 'password'
    click_button 'Login'
  end
end

ちなみにmacrosとは

パソコンで、複雑な操作の手順をあらかじめ登録しておき、必要なときに簡単に実行させる機能。マクロ機能。 macro(マクロ)の意味 - goo国語辞書

② 共通項目なので、こちらもrails_helper.rbに読み込みを記載
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods

  # 明示的にLoginMacrosの読み込みを記載
  config.include LoginMacros
end

実際にテストを作成

前述した通り、テストコードに絶対的な正解はないんだそう。ただ現状、自分の乏しい経験値では的確なコードを書くのはかなり難しい。たくさん書いて慣れていくしかないと思う。

require 'rails_helper'

RSpec.describe "AdminArticlesPreviews", type: :system do
  let(:user) { create(:user, :admin)}
  describe 'ログイン後' do
    describe '画像のコンテンツブロック挿入後' do
      context '画像のファイルをアップロードしていない場合' do
        it '記事のプレビューページを閲覧できる' do
          login_as(user)
          click_link '記事'
          click_link '新規作成'
          fill_in 'タイトル', with: 'test'
          click_button '登録する'
          click_link 'ブロックを追加する'
          click_link '画像'
          click_link 'プレビュー'
          switch_to_window(windows.second)
          expect(page).to have_content('test')
        end
      end
    end
  end
end

こんな感じで書いた。 テストを実行すると、

https://i.gyazo.com/8614491183ea222c5a20e3124df429cb.png

エラー発生

https://i.gyazo.com/119b410ef8f2863ce58d095b5f7caff6.png

https://i.gyazo.com/5ea029496fe685193fbbafeea55eb5c1.png

結論、テスト環境にもシードデータを追加することで解決。。

bundle exec rails db:seed_fu RAILS_ENV=test

seed-fuは、既に存在しているが変更したいレコードだけ更新したり、ファイル単位で実行できたり、簡単に書けるようなシンタックスシュガーがあったりど便利です。 railsで初期データを入れる(seed-fuの使い方) - Qiita

rails db:seedを何も考えずに使うと実行する度に同じデータが登録されてしまう。

もしくは、spec/spec_helper.rbに下記を記載

RSpec.configure do |config|
  config.before :suite do
    SeedFu.seed
  end
end

テスト実行の度にシードデータを入れている。

着眼点として

  • current_siteがnilである
  • そもそもSiteのデータ登録が必要?

という思考には至らなかった。もし思い至ってもシードデータをテスト環境に追加しようとは思えなかった。

click_buttonとclick_linkについて

RSpec Capybara href の無い a タグにハマる - かもメモ

自分は検証で調べてbtnならclick_button、見た目がボタンではなくただのリンクならclick_linkみたいな使い方をして来たけれど、aタグはリンクでないとマッチしないらしい。

https://i.gyazo.com/832461d576b7a9b4ea9aec54891c82e9.png

https://i.gyazo.com/46730b7fb7883fea893ad310217994aa.png

見た目がボタンならボタンというわけではないらしい。

参考にしたサイト

【Rails】はじめてのSystemSpec(RSpec) - Qiita

RSpec Capybara href の無い a タグにハマる - かもメモ

railsで初期データを入れる(seed-fuの使い方) - Qiita