LoginSignup
1
1

More than 5 years have passed since last update.

RSpec/FactoryBotでモデルのインスタンスメソッドを検証

Last updated at Posted at 2018-12-02

Modelにインスタンスメソッド定義した時にちゃんとメソッドが通るか rails console で確認したりするのですが、クラスの親子関係が複雑になると rails console でインスタンス作るのが面倒になります。
そういう時はFactoryBotを使ってテスト環境にインスタンス作成してspec書いた方が楽です。

spec書いた時に気づいたtraitの使い方とこういう時にtransient使えるなっていうメモ

想定モデル(適当)

  • ReservationとMenuは一対多の関係
  • ホットペッパービューティーみたいに一つの予約に、カットとかシャンプーとかのたくさんのメニューをいれれるイメージ
Reservation.rb
class Reservation
  has_many :menus, dependent: :destroy

  validates :costomer_name, presence: true
  validates :phone_number, presence: true

  # menuの合計金額を得るメソッド
  def total_price_from_menu
    total_price = Money.new(0)
    menus.each do |menu|
      total_price += menu.price
    end
    total_price
  end 
end
Menu.rb
class Menu
  belongs_to :reservation

  validates :name, presence: true
  validates :price_cents

  # Moneyオブジェクト
  monetize :price_cents
end

FactoryBot

  • Factoryを定義する
  • traitはfactoryの特定の状態に名前をつけて自由につけ外しができるようにする。下記ではreservationをcreateした時に子要素のmenuも同時に生成するようにtraitを定義した。
  • transientは作成するデータと関係ないattributeを生成する。下記ではtransientのmenu_numの数だけ子要素のインスタンスを作成する。
spec/factories/reservations.rb
FactoryBot.define do
  factory :reservation do
    customer_name { "山田太郎" }
    phone_number { "00000000000" }
  trait :with_menus do
    transient do
      menu_num { 1 }
    end
    after(:create) do |reservation, evaluator|
      evaluator.menu_num.times do
        create(:menu, reservation: reservation)
      end
    end
  end
end
spec/factories/menus.rb
FactoryBot.define do
  factory :menus do
    association :reservation, factory: :reservation
    name { "カット" }
    price { "1000" }
  end
end

RSpec

  • テストの実行
  • with_menuで子要素が作られる
  • menu_numで引数を指定することで任意の数のインスタンスを作れる
  • インスタンスメソッドが期待どうりの挙動をするか確認する
spec/app/models/reservation_spec.rb
require 'rails_helper'

RSpec.describe Reservation, type: :model do
  describe "#total_price_from_menus" do
    let(:reservation) { create(:reservation, with_menu, menu_num: 2) }

    it "期待通りの合計金額になる" do
      expect(reservation.total_price_from_menu.format).to eq "200円"
    end
  end
end

参考: traitの切り替えやassoiationについては以下の記事が詳しい

FactoryBot(旧FactoryGirl)で関連データを同時に生成する方法いろいろ
FactoryGirlのtransientとtraitを活用する

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1