🐘
【Rails】Factorybot の trait, transient, evaluator
概要
Rails でテストデータを作成するときに FactoryBot を使う現場は多いと思います。
今回は FactoryBot で頻出する trait
, transient
, evaluator
について整理していきます。
trait
trait
はファクトリー(テストデータのテンプレートを定義するもの)に属性や振る舞いをグループ化して定義することができます。
また、再利用可能なパーツに分けることができ、コードの重複を防ぐことができます。
FactoryBot.define do
factory :user do
name { "MyString" }
age { 20 }
trait :name_is_john do
name { "John" }
end
end
end
# デフォルト
user = create(:user)
user.name
=> "MyString"
# trait で定義した name_is_john を使用
user = create(:user, :name_is_john)
user.name
=> "John"
また、関連テーブルのレコードも一緒に作成することもできます。
例えば User
と Article
が 1対N のような関係のとき、書くことができます。
FactoryBot.define do
factory :user do
name { "MyString" }
age { 20 }
# article を2つ作成
trait :with_two_articles do
after(:create) do |user|
create_list(:article, 2, user: user)
end
end
end
end
user = create(:user, :with_two_articles)
user.articles.count
=> 2
transient
transient
は一時的な属性を定義するときに使用できます。
主に、ファクトリー内でデータを生成するための補助的な情報を提供するために使用されます。
FactoryBot.define do
factory :user do
name { "MyString#{"(admin)" if is_admin}" }
age { 20 }
transient do
is_admin { false }
end
end
end
user = create(:user, is_admin: true)
user.name
=> "MyString(admin)"
user = create(:user, is_admin: false)
user.name
user.name
=> "MyString"
上記のように、任意の属性 id_admin
を定義することで、データ生成時に任意の値をもたせることで、
柔軟なデータ作成ができるようになります。
evaluator
evaluator
は transient
で定義した属性を、after(:create)
などのコールバック内で取得するのに使用します。
先程のように、 User
と Article
が 1対N の場合、以下のコードが存在するとします。
FactoryBot.define do
factory :user do
name { "MyString" }
age { 20 }
transient do
has_articles_count { 3 }
end
after(:create) do |user, evaluator|
create_list(:article, evaluator.has_articles_count, user: user)
end
end
end
これで、has_articles_count
に作成したい記事数を指定してあげると、
User
の作成と同時に Article
を指定した数だけ作成してくれます。
user = create(:user, has_articles_count: 5)
user.articles.count
=> 5
何も指定しないと、デフォルトで指定している3つが作成されます。
user = create(:user)
user.articles.count
=> 3
まとめ
役割 | 使い時 | |
---|---|---|
trait | ファクトリーに属性や振る舞いをグループ化して定義することができる。 | 決まった属性のテストデータを作成したいとき。 |
transient | 一時的な属性を定義するときに使用できる。 | 作成するテストデータの値を柔軟に変更したいとき。 |
evaluator | transient で定義した属性を、after(:create)などのコールバック内で取得するのに使用する。 | コールバック内で transient で定義した属性の値を使用したいとき。 |
Discussion