こんにちは、Railsエンジニアにょけんです。
RSpecの導入・設定方法と、テストデータ生成用のFactoryBotの使い方をまとめました。
- RSpec→Railsの動作テスト用gem
- FactoryBot→テスト用のデータベース登録をラクに行うgem
①開発環境とテスト環境にだけ、RSpec・FactoryBotを追加
まずはおなじみのGemfileに追加。
ですが、読み込むのは開発環境とテスト環境だけで、本番環境には読み込まない点に注意しましょう。
[Gemfile]
group :development, :test do gem 'rspec-rails' gem "factory_bot_rails" end
②「RSpec」をアプリで使えるように設定
「bundle install」が完了したら、次にアプリでRSpecを使うための設定を行います。
まずは、以下のコマンドを実行。
[ターミナル]
$ bin/rails generate rspec:install
実行後、以下ファイルが生成されます。
Running via Spring preloader in process 28211 create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb
- .rspec→RSpec用の設定ファイル
- spec→specファイル(テストファイル)関連を格納するディレクトリ
- spec_helper.rb&rails_helper.rb→RSpecのカスタマイズ用ヘルパーファイル
.rspecに「–format documentation」を追加することで、テスト結果を読みやすいドキュメント形式に変更できます。
※.rspecが見当たらない場合は、「open -e .rspec」で開ける
[.rspec]
--require spec_helper --format documentation
③rails g実行時に同時生成するSpecファイルを設定する
[config/application.rb]にて、「rails generate ◯◯」実行時に同時生成するSpecファイルを設定できます。
“config.generators do |g|”内の各値を「false」にすると、不要なファイルを作成しません。
以下は参考例です。
[config/application.rb]
require_relative 'boot' require 'rails/all' Bundler.require(*Rails.groups) module Projects class Application < Rails::Application config.load_defaults 5.1 # ///省略/// config.generators do |g| g.test_framework :rspec, view_specs: false, helper_specs: false, routing_specs: false end end end
- view_specs: false
→UIテストは「FeatureSpec」という別テストで行うのが通例なので、ビューの作成はスキップする。 - helper_specs: false
→ヘルパーファイル用のSpecファイルを作成しない。
※ヘルパーファイル=Railsがコントローラごとに作成するファイル - • routing_specs: false
→config/routes.rb用のSpecファイルを作成しない。
[config/application.rb]内に、「fixtures: false」という一文がある場合は削除しておきましょう。
削除すると、モデルを作成時に自動でSpecファイルを作成してくれるので便利です。
④FactoryBotを使ってみよう
FactoryBotは、テスト用のデータベース作成ツールでしたね?
てわけで、テストで使うデータを登録していきましょう。
1.ファクトリファイルを生成
例えば、Userモデルのサンプルデータを作りたい場合は、以下を実行します。
[ターミナル]
$ bin/rails g factory_bot:model user
[spec/factories/users.rb]が生成されるので、設定を追加していきます。
[spec/factories/users.rb](カスタマイズ後)
FactoryBot.define do factory :user do sequence(:name) { |n| "TestUser#{n}" } sequence(:email) { |n| "Test#{n}@example.com" } password "i-am-test-user" end end
※sequenceを使うと、値の重複を避けられます。
2.ファクトリファイルを生成
上記の手順を踏めば、テスト内で「FactoryBot.create(:user)」を使って新しいユーザーを作成できます。
例として、以下2つのバリデーションをチェックしたい場合を考えましょう。
- validates :name, presence: true(nameが空欄だと無効である)
- validates :email, uniqueness: true(emailが重複していると無効である)
[spec/models/user.rb]
require 'rails_helper' RSpec.describe User, type: :model do describe 'Userバリデーションチェック' do it 'nameが空欄の場合、User作成不可' do @user = FactoryBot.build(:user, name: '') expect(@user.valid?).to eq(false) end it 'emailが重複している場合、User作成不可' do @user = FactoryBot.create(:user) @other_user = FactoryBot.build(:user, email: 'test0@example.com') expect(@user.valid?).to eq(false) end end end
【応用編】モデル同士の関連付けを定義
今までのテストはRailsデフォルトの「fixture」(.ymlファイルを使ったテストデータ生成)でも可能なんですが、「FactoryBot」の真価はここからです。
モデル同士の関連付けがカンタンなんですよ。
例えば、「Userモデル」「Taskモデル」「Noteモデル」があるとします。
Userごとに複数のTaskを持っていて、さらにTaskごとに複数のNoteが存在している想定。
つまり、「User:Task = 1: 多」「Task: Note = 1:多」です。
まず、新たに出てきた「Taskモデル」「Noteモデル」のSpecファイルを作成しましょう。
[ターミナル]
$ bundle exec rails g factory_bot:model task
$ bundle exec rails g factory_bot:model note
生成したファイルに、設定を追加します。
[spec/factories/tasks.rb]
FactoryBot.define do factory :task do sequence(:name) { |n| "Task #{n}" } description "A test task." association :user end end
[spec/factories/notes.rb]
FactoryBot.define do factory :note do message "this is note" association :task user { task.user } end end
このように関連を明記しておくと、Noteのテストで「@note = FactoryBot.create(:note)」と書くだけで、勝手にUserとTaskも生成してくれます。
つまり、
[spec/models/note_spec.rb]
require 'rails_helper' RSpec.describe Note, type: :model do # ファクトリで関連するデータを生成する it "generates associated data from a factory" do note = FactoryBot.create(:note) puts "This note's task is #{note.task.inspect}" puts "This note's user is #{note.user.inspect}" end end
といったように、note.taskやnote.userが一発で使えるんです。
いや〜便利。
Noteのテストがしたいのに、いちいち関連するUserやTaskの生成を書くのはダルいですもんね。
⑤RSpecでテストを実行してみよう
RSpecのテストは、以下コマンドで実行できます。
[ターミナル]
$ bundle exec rspec
もちろん、ファイルや行数を指定して実行することもできます。
[ターミナル]
# ファイルを指定してRSpecを実行 $ bundle exec rspec spec/models/users_spec.rb # users_spec.rbの10行目にあるテストを実行 $ bundle exec rspec spec/models/users_spec.rb:10
ついでに「spring-commands-rspec」というgemを開発環境に入れると、テストの起動時間が早くなります。
以下の手順を実行しましょう。
1.[Gemfile]
group :development do gem 'spring-commands-rspec' end
2.[ターミナル]
$ bundle install
3.[ターミナル]
$ bundle exec spring binstub rspec
4.[ターミナル]
$ bin/rspec
上記の設定を追加した場合、「bundle exec」コマンドではなく「bin/rails」コマンドになるのでご注意を。
おまけ:FactoryBotとfixtureの違い
今回紹介した「FactoryBot」と、Railsデフォルトのテストデータ生成用ツール「fixture」 の違いをカンタンにまとめました。
ちなみに、fixtureは「.ymlファイル」を使ってテスト用データを生成します。
動作 | 追加設定 | 耐久性 | ActiveRecordの使用 | |
FactoryBot |
普通 |
必要 |
丈夫 |
使用 |
fixture |
早い |
不要 |
もろい | 不使用 |
一長一短ありますが、注目は1番右の「ActiveRecord」です。
ActiveRecordはRailsのデータベース生成に使う仕組みなんですが、fixtureはまさかのコレと別の仕組みでデータベースを組んでいるんですよね。
そのため、テストでバリデーションのチェックが行えない場合があったりと、なかなかに微妙です。
基本的に「FactoryBot」などのファクトリを使う方が無難。
コメント