RSpec学習メモ(everyday Rails RSpecによるRailsテスト入門 第4章)

<アプリケーションにファクトリを追加する>

$ bundle exec rails g factory_bot model:user

# specディレクトリ内にfactoriesという新しいディレクトリが作られる。そしてその中にusers.rbという名前のファイルが作成される。

 

<spec/factories/users.rb>

FactoryBot.define do

  factory :user do

    first_name "Aaron"
    last_name "Sumner"
    email "tester@example.com"
    password "dottle-nouveau-pavilion-tights-furze"

  end

end

 

こうすると、テスト内でFactoryBot.create(:user)と書くことで新しいユーザーを作成することができる。

FactoryBot.create(:user)を使ってテストデータを作れば、そのユーザーは毎回基本的に上記で設定したデータのものとなる。

 

<spec/models/user_spec.rb>

describe User do
  # 有効なファクトリを持つこと

  it "has a valid factory" do

    expect(FactoryBot.build(:user)).to be_valid

  end

end

 

FactoryBotを使用することでこのように簡潔に書き換えることができる。

ここではFactoryBot.buildを使用したので、新しいユーザーはインスタンス化されるだけで、保存はされない。

 

ポイント

FactoryBot.buildを使うと新しいテストオブジェクトをメモリ内に保存する。FactoryBot.createを使うとアプリケーションのテスト用データベースにオブジェクトを永続化する。

 

---------------------------------------------------------------------------------------

 

<シーケンスを使ってユニークなデータを作成する>

FactoryBotではシーケンスを使って、ユニークバリデーションを持つフィールドを扱うことができる。

 

<spec/factories/users.rb>

FactoryBot.define do

  factory :user do

    first_name "Aaron"

    last_name  "Sumner"

    sequence(:email) { |n| "tester#{n}@example.com" }

    password "dottle-nouveau-pavilion-tights-furze"

  end

end

 

新しいユーザーを作成するたびに、、tester1@example.com tester2@example.com というように、ユニークで連続したメールアドレスが設定される。

 

---------------------------------------------------------------------------------------

 

<ファクトリ関連を扱う>

FactoryBotは他のモデルと関連を持つモデルを扱うのにとても便利である。

 

<spec/factories/users.rb>

FactoryBot.define do
  factory :user, aliases: [:owner] do

    first_name "Aaron"
    last_name "Sumner"
    sequence(:email) { |n| "tester#{n}@example.com" }

    password "dottle-nouveau-pavilion-tights-furze"

  end

end

 

<spec/factories/notes.rb>

FactoryBot.define do

  factory :note do

    message "My important note."

    association :project

    user { project.owner }

  end

end

 

<spec/factories/projects.rb>

FactoryBot.define do

  factory :project do

    sequence(:name) { |n| "Project #{n}" }

    description "A test project."
    due_on 1.week.from_now
    association :owner

  end

end

 

Noteはプロジェクトとユーザーの両方に属している。しかし、テストのたびに毎回プロジェクトとユーザーを手作業で作成したくはない。今作りたいのはメモだけである。

 

ポイント

FactoryBotを使用する際は、ユーザーファクトリに対してownerという名前で参照される場合があると伝えなくてはならない。そのためにaliasを使用する。

 

<app/models/project.rb>

class Project < ApplicationRecord

  validates :name, presence: true, uniqueness: { scope: :user_id }

 

  belongs_to :owner, class_name: User, foreign_key: :user_id

  has_many :tasks

  has_many :notes

end

 

---------------------------------------------------------------------------------------

 

<ファクトリ内の重複をなくす>

FactoryBotでは同じ型を作成するファクトリを複数定義することもできる。

特定のファクトリを使って作成するインスタンスのクラス名と、既存のファクトリと異なるインスタンスの属性値を指定する。そしてその作成したインスタンスの名前を引数に渡すことができる。

 

重複を減らすテクニックが二つある。

①ファクトリの継承を使ってユニークな属性だけを変えること。

②トレイと(trait)を使ってテストデータを構築すること。

 

---------------------------------------------------------------------------------------

 

<ファクトリを安全に使用する>

ファクトリを使用するとテスト中に予期しないデータが作成されたり、無駄にテストが遅くなったりする原因となる。

可能な限りFactoryBot.createではなくFactoryBot.buildを使用することで、テストデータベースにデータを追加する回数が減るので、パフォーマンス面のコストを削減することができる。