Rspecを書いてみよう
初めてテストコードを書いたのでおさらいのためにまとめてみます。
RailsはMInitestというテスティングフレームワークを備えていますが今回は
以前作った簡単なCRUDアプリ
を元にRspec
を導入してテストを書いてみました。
テストが必要なほどの機能はないのですが練習のため。
2つの違いはよくわかってませんがRspecの方が利用率は高いそうです。
ではまずは導入からやっていきます。
必要gemのインストール
必要なgemを4つインストールします。
group :development, :test do gem 'rspec-rails' gem 'factory_bot_rails' end group :test do gem 'capybara' gem 'webdrivers' end
rspec-rails
テスティングフレームワーク。
これがないと始まらない。
GitHub - rspec/rspec-rails: RSpec for Rails 5+
factory_bot_rails
テスト用のデータを簡単に作成できるgem。
GitHub - thoughtbot/factory_bot_rails: Factory Bot ♥ Rails
capybara
E2Eテスティングフレームワーク。
ブラウザでテストしてくれる。
GitHub - teamcapybara/capybara: Acceptance test framework for web applications
webdrivers
調べたんですがあんまりわかってません。
capybaraとセットで使われるっぽい。
selenium-webdriver
、chromedriver-helper
の代わりにこのwebdrivers
1つでいいみたいです。
GitHub - titusfortner/webdrivers: Keep your Selenium WebDrivers updated automatically
bundle install
でインストールします。
諸々の設定
rails g rspec:install
とすると
Running via Spring preloader in process 63316 create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb
これらが作成されます。
.rspec
に--format documentation
を追加するとテスト結果の表示が変わります。
お好みで設定しましょう。
rails_helper.rbの
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
これのコメントアウトを外すとspec/support以下のファイルを読み込みます。
モジュールなどを作成する場合はsupportディレクトリを作成し、その中に置きます。
このアプリにログイン機能はまだないので以下は例です。
# support/system_helper.rb module LoginModule def login(user) visit '/login' fill_in 'Name', with: user.name fill_in 'Email', with: user.email fill_in 'Password', with: '00000000' click_button 'Login' end end
support/capybara.rbを作成して
RSpec.configure do |config| config.before(:each, type: :system) do driven_by :selenium_chrome_headless end end
ドライバーの設定もしておきます。
selenium_chrome_headless
を指定しておくとテスト実行の度にブラウザを立ち上げずにテストしてくれます。
テスト用データの作成
rails g rspec:model user
このコマンドでmodels/user_spec.rbとfactories/user.rbが作成されます。
FactoryBot.define do factory :user do end end
こちらがfactories/user.rbの中身です。
ここでテスト用のデータを作成します。
userモデルとスキーマのusersテーブルは
class User < ApplicationRecord validates :name, presence: true enum gender: { male: 0, female: 1, secret: 2 } end
create_table "users", force: :cascade do |t| t.string "name", null: false t.integer "gender", default: 0, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false end
こんな感じです。
FactoryBot.define do factory :user do name { 'test_name' } gender { 'male' } end end
名前と性別を設定しておきました。
テストで使うデータの初期値を設定しておく、というイメージです。
また、rails_helper.rbに
RSpec.configure do |config| config.include FactoryBot::Syntax::Methods end
これを追加しておくと、テストでデータを作るときに
# 設定なし user = FactoryBot.build(:user) # 設定あり user = build(:user)
このように省略できるので設定しておきます。
テストの作成
ようやくテストの作成です。
今回はバリデーションに関するテストを作ってみます。
先ほど作成したmodels/user_spec.rbに
require 'rails_helper' RSpec.describe User, type: :model do describe 'バリデーション' do it '全てのフォームが正常な場合に成功する' do user = build(:user) expect(user).to be_valid expect(user.errors).to be_empty end it 'Nameが空の場合に失敗する' do user = build(:user, name: nil) expect(user).to be_invalid expect(user.errors[:name]).to eq ['を入力してください'] end end end
2つのテストを書いてみました。
1つ目のテストを説明すると、
・user = build(:user)
factories/user.rbの情報を元にユーザーを作成しuserに代入
・expect(user).to be_valid
userがバリデーションを通ることを期待
・expect(user.errors).to be_empty
user.errorsが空であることを期待
となります。
2つ目だと
・user = build(:user, name: nil)
初期値を元にするがnameは空にする
・expect(user).to be_invalid
userがバリデーションに引っかかることを期待
・expect(user.errors[:name]).to eq ['を入力してください']
エラー文、「を入力してください」と表示されることを期待
となります。
それではテストを実行してみましょう。
bundle exec rspec
とすると
通りました。
最後に
ほんとに簡単なところだけですがテストを作って実行するところまでできました。実装のコードは間違っていたらエラーが出ますが、テストはそもそもテストコードをちゃんと書かないと意味を成さない気がするので気を付けたいです。何か間違いなどありましたらコメントいただけると嬉しいです。
では今回もありがとうございました。
参考サイト
E2Eテスト
RSpecとminitestのおおまかな違い - Qiita
FactoryBotでテストデータ作成する方法 - Qiita
【Rails】『RSpec + FactoryBot + Capybara + Webdrivers』の導入&初期設定からテストの書き方まで | vdeep