ここでは、Fabrication のサイトを日本語に直して、自己解釈して補完しながら説明していきます。
Fabricationとは
これはオブジェクト生成ライブラリで、
オブジェクトの概略だけを定義し、素早くオブジェクトを使うことができるものである。
サポートしているオブジェクトタイプは以下のものなどがある。
- ActiveRecord Models
- Mongoid Documents
- Sequel Models
- DataMapper Resources
- ・・・
設定
Gemfile に Fabrication を記載し、bundle install すれば使える
デフォルトでは以下にFabrication関連のソースを置くと、自動ロードされる。
1
2
| spec/fabricators/**/*fabricator.rb
test/fabricators/**/*fabricator.rb
|
設定を変更したい場合は以下のように、Fabrication.configureで設定変更できる。
1
2
3
4
| Fabrication.configure do |config|
config.fabricator_path = 'data/fabricators' #Fabrication関連の定義を置くパス
config.path_prefix = Rails.root #ファイルシステムへの許可範囲
end
|
引数
1
2
| class Person; end
Fabricator(:person) #引数がFabricatiorオブジェクトになる。クラス名のシンボルである必要がある
|
1
| Fabricator(:adult, from: :person) #from: :symbolized_class_nameのクラス名を変えて:adultというFabricatiorオブジェクトが定義できる
|
属性
Fabricator ブロックには変数が必要ではないが、1つ提供される。属性リスト作成時に、宣言もされる。
1
2
3
4
| Fabricator(:person) do
name 'Greg Graffin'
profession 'Professor/Musician'
end
|
属性には変数を渡すことができる
1
2
3
4
| Fabricator(:person) do
name { Faker::Name.name }
profession { %w(Butcher Baker Candlestick\ Maker).sample }
end
|
属性は処理順に宣言され、上記フィールドのブロック変数を用いることができる。
1
2
3
4
| Fabricator(:person) do
name { Faker::Name.name }
email { |attrs| "#{attrs[:name].parameterize}@example.com" }
end
|
予約語
予約語名をブロック変数と一緒に使うことで属性として参照できる
1
2
3
| Fabricator(:person) do |f|
f.alias 'James Bond'
end
|
関連
他のFabricatorに関連付ける場合は、属性名を書くだけでいい。
これで、「belongs_to」の関連を表現できる。
1
2
3
4
5
6
7
| Fabricator(:person) do
vehicle
end
↑↓等価
Fabricator(:person) do
vehicle { Fabricate(:vehicle) }
end
|
1
2
3
4
5
6
7
| Fabricator(:person) do
ride(fabricator: :vehicle)
end
↑↓等価
Fabricator(:person) do
ride { Fabricate(:vehicle) }
end
|
countパラメータを使うことで、配列オブジェクトを生成できる。
1
2
3
4
| Fabricator(:person) do
open_souce_projects(count: 5)
children(count: 3) { |attrs, i| Fabricate(:person, name: "Kid #{i}") }
end
|
継承
他の Fabricators から属性を継承する場合は、「:from」 を使う
1
2
3
4
5
6
7
| Fabricator(:llc, from: :company) do #クラスの属性とその値を全て継承する
type "LLC"
end
Fabricator(:llc, class_name: :company) do # class_name: でクラスの属性のみを継承する
type "LLC"
end
|
初期化
オブジェクトの初期化を通常の方法でしてほしくないときは、
initialize_withを以下のようにオーバーライドすればよい。
1
2
3
4
| Fabricator(:car) do
initialize_with { Manufacturer.produce(:new_car) }
color 'red'
end
|
コールバック
Fabricationのビルドにフックするには、after_build、after_create を使う。
1
2
3
4
| Fabricator(:place) do
after_build { |place| place.geolocate! } #ビルド後=保存する前
after_create { |place| Fabricate(:restaurant, place: place) } #保存した後
end
|
オブジェクトに引数を与えたときのコンストラクタでコールバックするときは、on_initを使う。
1
2
3
| Fabricator(:location) do
on_init { init_with(30.284167, -81.396111) }
end
|
コールバックはスタックになっているので、並列にFabricatorを宣言できるし、継承しても大丈夫。
エイリアス
Fabricatior呼び出し時に:aliasesオプションをつけるとエイリアスが付けれる。
1
| Fabricator(:thingy, aliases: [:widget, :wocket]) #Fabricateを :thingy,:widget, :wocketどれでも呼び出せる
|
一時属性
Fabricator内で一時属性を変数として持てるが、クラス生成時にはセットされない。
一時属性は、クラスが生成されるまでの間は普通の属性と同じように扱えるが、生成時に取り除かれる。
1
2
3
4
5
6
7
8
9
10
| Fabricator(:city) do
transient :asian
name { |attrs| attrs[:asian] ? "Tokyo" : "Stockholm" }
end
Fabricate(:city, asian: true)
# => <City name: 'Tokyo'>
Fabricator(:the_count) do
transient :one, :two, :three #複数定義可
end
|
リロード
Fabricationがロードされた状態にリセットする
1
| Fabrication.clear_definitions
|
基本
Fabricateオブジェクトを作成する簡単な方法は、クラス名を渡すだけでいい。
これで、PersonのインスタンスがFabricatorとして定義される。
Fabricator作成時に、引数としてハッシュを渡せば、属性の追加や、上書きができる。
1
| Fabricate(:person, first_name: "Corbin", last_name: "Dallas")
|
Fabricating With Blocks
Fabricateのブロックの引数にハッシュ値を渡せば、オブジェクト生成時に定義され利用できる。
1
2
3
4
| Fabricate(:person, name: "Franky Four Fingers") do
addiction "Gambling"
fingers(count: 9)
end
|
ビルド
データベースにオブジェクトを持続させたくないときは Fabricate.build を使う。
1
| Fabricate.build(:person)
|
下記のように、Fabricate.build内でFabricateが呼ばれていてもオブジェクトは持続せず、buildのときの動作と同じになる。
1
2
3
| Fabricate.build(:person) do
cars { 2.times { Fabricate(:car) } }
end
|
属性のハッシュ
オブジェクトを生成せずに、属性だけを生成してハッシュで返したい場合は以下のようにする。
1
| Fabricate.attributes_for(:company)
|
Sequences
Sequencesはそのプロセスにおいての、ユニークな連続した数値が得られる。
Sequencesは指定がなければ、0からはじまる。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| Fabricate.sequence #実行するたびにインクリメントされていく
# => 0 #1回目
# => 1 #2回目
# => 2 #3回目
Fabricate.sequence(:name) #引数を渡せば独自の数値でインクリメントされる
# => 0
# => 1
# => 2
Fabricate.sequence(:number, 99) #第2引数の数値は開始の数値
# => 99
# => 100
# => 101
Fabricate.sequence(:name) { |i| "Name #{i}" } #ブロックで渡してもインクリメントされる
# => "Name 0"
# => "Name 1"
# => "Name 2"
Fabricate(:person) do #例
ssn { sequence(:ssn, 111111111) }
email { sequence(:email) { |i| "user#{i}@example.com" } }
end
# => <Person ssn: 111111111, email: "user0@example.com">
# => <Person ssn: 111111112, email: "user1@example.com">
# => <Person ssn: 111111113, email: "user2@example.com">
|
Rails 3
Rails 3でFabricatorsをモデル生成時に一緒に生成したい場合は、config/application.rb に設定を書く。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # rspecの場合
config.generators do |g|
g.test_framework :rspec, fixture: true
g.fixture_replacement :fabrication
end
# test/unitの場合
config.generators do |g|
g.test_framework :test_unit, fixture_replacement: :fabrication
g.fixture_replacement :fabrication, dir: "test/fabricators"
end
# minitestの場合
config.generators do |g|
g.test_framework :mini_test, fixture_replacement: :fabrication
g.fixture_replacement :fabrication, dir: "test/fabricators"
end
|
上記設定後、下記コマンドでFabricationのファイルができる。
1
2
3
4
| $ rails generate model widget #コマンド
spec/fabricators/widget_fabricator.rb
Fabricator(:widget) do #中身
end
|
参考リンク