【Rails】RSpecとFactroyBotの導入・設定まとめ

スポンサーリンク

 

こんにちは、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ファイルを作成しない。
「fixtures: false」の一文は削除 [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
これで、binディレクトリ内に「rspec」という名前の実行用ファイルが作成されます。

 

4.[ターミナル]

$ bin/rspec

上記の設定を追加した場合、「bundle exec」コマンドではなく「bin/rails」コマンドになるのでご注意を。

 

 

おまけ:FactoryBotとfixtureの違い

今回紹介した「FactoryBot」と、Railsデフォルトのテストデータ生成用ツール「fixture」 の違いをカンタンにまとめました。

ちなみに、fixtureは「.ymlファイル」を使ってテスト用データを生成します。

  動作 追加設定 耐久性 ActiveRecordの使用
FactoryBot

普通

必要

丈夫

使用

fixture

早い

不要

もろい 不使用

 

一長一短ありますが、注目は1番右の「ActiveRecord」です。

ActiveRecordはRailsのデータベース生成に使う仕組みなんですが、fixtureはまさかのコレと別の仕組みでデータベースを組んでいるんですよね。

そのため、テストでバリデーションのチェックが行えない場合があったりと、なかなかに微妙です。

基本的に「FactoryBot」などのファクトリを使う方が無難。

スポンサーリンク