RSpec

【RSpec初級編】FactoryBotを用いてテストコードを効率化する方法について解説

RSpec

 

今回はRSpecのテストコードを効率化できるツール「FactoryBot」について初心者向けに解説したいと思います。

FactoryBotを用いずともテストコードを書くことは可能ですが、それではダラダラと長いコードになってしまいます。FactoryBotの使い方をマスターし、より洗練されたテストコードが書けるよう学習していきましょう。

FactoryBotとは

FactoryBotとは、サンプルデータ(≒ ダミーのインスタンス)を簡単に作成することができるテストツールです。「factory_bot_rails」というGemをインストールすることでFactoryBotが使えるようになります。

では、FactoryBotを使用することでどのくらいテストコードが効率化できるのか見ていきましょう。

例えば以下のコードでは、nicknameとemailの値が空である場合はユーザー登録ができないことをテストしています。

require 'rails_helper'

describe User do
  context 'not be able to create' do
    it "is invalid without a nickname" do
      user = User.new(nickname: "", email: "aaa@gmail.com", password: "00000000", password_confirmation: "00000000")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end
  end
end


describe User do
  context 'not be able to create' do
    it "is invalid without an email" do
     user = User.new(nickname: "test", email: "", password: "00000000", password_confirmation: "00000000")
     user.valid?
     expect(user.errors[:email]).to include("can't be blank")
    end
  end
end

 

「user = User.new(~~~~)」を毎回の実行していることが分かると思います。

しかし、FactoryBotを使用することで「use = User.new(~~~~)」の記述を1箇所にまとめることができ、よりシンプルなコードにすることができます。言い換えれば、毎回インスタンスを生成する必要がなくなるということです。

ではFactoryBotを使用した場合の記述例を見ていきましょう。

# spec/factories/users.rb

FactoryBot.define do
  factory :user do
    nickname              {"test"}
    email                 {"test@gmail.com"}
    password              {"12345678"}
    password_confirmation {"12345678"}
  end
end
# spec/models/user_spec.rb

describe User do
  context 'not be able to create' do
    it "is invalid without a nickname" do
      user = FactoryBot.build(:user, nickname: "")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end

    it "is invalid without an email" do
      user = FactoryBot.build(:user, email: "")
      user.valid?
      expect(user.errors[:email]).to include("can't be blank")
    end
  end
end

 

spec/factories/users.rbでユーザーのサンプルデータを作成しておき、実際のテストコードではFactoryで定義したデータの内、テストしたい部分だけを上書きしています。

具体的に説明すると、以下のコードではuserのFactoryBotを呼び出し、nicknameだけは空の状態で上書きしています。

user = FactoryBot.build(:user, nickname: "")

 

さらに言うと、以下の2つのコードは同じことを意味しています。

user = User.new(nickname: "test", email: "test@gmail.com", password: "12345678", password_confirmation: "12345678")
# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname              {"test"}
    email                 {"test@gmail.com"}
    password              {"12345678"}
    password_confirmation {"12345678"}
  end
end

# spec/models/user_spec.rb
user = FactoryBot.build(:user)

 

このように、FactoryBotを使用することで何度も使用するデータをあらかじめ作成しておくことができます。テストコードではそれらを呼び出すだけなので非常に便利ですね。

FactoryBotの導入

FactoryBotの使い方が分かったので、次はFactoryBotの導入について解説します。

まずはGemfileのdevelopment/test環境に「factory_bot_rails」を記述しましょう。記述後はbundle installを実行してください。

group :development, :test do
  # 省略
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end
% bundle install

 

続いてfactoriesを作成するため、以下のコマンドを打ち込みます。

そうすることでfactoriesディレクトリ直下にusers.rbが作成されます。

% rails g factory_bot:model user
上記はUserモデルをテストする場合のコマンドになります。モデル名は適宜変更してください。

 

作成されたusers.rbを確認すると以下のように雛形が出来上がっています。後はここにサンプルデータを記載するだけです。

FactoryBot.define do
  factory :user do

  end
end

よりコードをスッキリさせるには

ここまででも大分綺麗なコードにはなりました。

しかし以下のようにFactoryBotという表現を省略し、よりコードをすっきりさせることができます。

user = FactoryBot.build(:user, nickname: "")
↓
user = build(:user, nickname: "")
user = FactoryBot.build(:user, email: "")
↓
user = build(:user, email: "")

 

上記のようにFactoryBotという文言を省略するには、spec/rails_helper.rbを以下のように編集する必要があるので忘れずに追記するようにしましょう。

RSpec.configure do |config|
  # 下記を追記
  config.include FactoryBot::Syntax::Methods

  #省略

end

Fixtureとの比較

Railsではサンプルデータを生成する手段として、Fixture(フィクスチャ)と呼ばれる機能がデフォルトで提供されています。FixtureはYAML形式のファイルです。

例えば、ユーザーのサンプルデータをFixtureで作成すると以下のようになります。

# users.yml

person:
  name: "test"
  email: "test@gmail.com"
  password: "12345678"
  password_confirmation: "12345678"

 

そしてそのサンプルデータを呼び出すには、テストコードで以下の記述をします。

users(:person)

 

FactoryBotを同じく、比較的簡単にサンプルデータを作成することができましたね。

ただFixtureには1つ大きな欠点があります。

それは、RailsはFixtureのデータを読み込む際にActiveRecordを使用しないということです。言い換えれば、モデルのバリデーションのような重要な機能が無視されてしまうということです。

そのため個人的にはFactoryBotの使用をおすすめします。

まとめ

  • FactoryBotとは、サンプルデータを簡単に作成することができるテストツール
  • FactoryBotを使用するにはfactory_bot_railsというGemをインストールする必要がある
  • 似たような機能にFixtureがあるが、ActiveRecordを使用しないという欠点がある

参考

Everyday Rails

 

 

今回はRSpecのテストコードを効率化できるツール「FactoryBot」について初心者向けに解説しました。今後RSpecのサンプルデータを作成する際はFactoryBotを使用するよう心がけていきましょう。