FactoryGirlを使ってみる
何やら色々Railsな情報を見てるとFactoryGirlっていうのがやたらと目に入ってくるので調べたりしつつちょっと使ってみた。単純に言うとテストで使用するフィクスチャを作成出来る物な模様
ActiveRecordにもfixtureな機能自体はあるけど、こっちはyamlとかで定義したりすると思うのだけど、事細かいリレーション構造とかだとテストデータをどう表現するのかはちょっと謎。っていうかそこまで使いこなせてないっていうオチな気もするけど
とりまぁ使ってみる
導入
Gemfileに
gem "factory_girl_rails", :group => [:development, :test]
を記述して、bundle installしておく。んで
rails g factory_girl:model モデル
な感じでファイルを生成する。RSpecとかの場合にはspec/factoriesディレクトリ内にファイルが生成される模様(RSpecじゃない場合にはtest/factories)
んでもって、ドキュメント通りにテストで使用する環境によってFactoryGirlなメソッドをincludeしちゃったりする(しなくてもFactoryGirlクラスのメソッドを使う事で出来るのかも、それは未検証)。今回はRSpecを使ってるんでspec_helper.rbに
RSpec.configure do |config|
# 追加
config.include FactoryGirl::Syntax::Methods
end
を追加
モデル仕様
- Entry.categoryでカテゴリー(Category)参照を取得できる
- Category.entryでカテゴリーを参照しているエントリー(Entry)参照を取得できる
- Category.parent_categoryでカテゴリーが参照している親カテゴリーを取得できる
- Category.sub_categoriesでカテゴリーを参照している子カテゴリーを参照できる
っていうような仕様がぶち込まれている。それをやってるのがhas_and_belongs_to_many辺り
んまぁ仕様的なはこんなもんかなと。あとはspec/factories等やモデルテストを書く
spec/factories/categories.rb
rails g factory_girl:model category
で生成したFactoryGirlの定義を書く
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :category1, :class => Category do
name "A"
end
factory :category2, :class => Category do
name "B"
association :parent_category, :factory => :category1
end
end
2つのカテゴリーを定義するけど、カテゴリーBはカテゴリーAの子カテゴリーとなりCategoryクラスのparent_categoryを参照する事で親カテゴリーなカテゴリーAを取得できるっていうような形になっているので、associationでカテゴリーAなfactoryを指定する
spec/factories/entries.rb
rails g factory_girl:model entry
で生成したFactoryGirlの定義を書いていく
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :entry, :class => Entry do
title "test"
content "test"
after :create do |e|
e.category << FactoryGirl.create(:category2)
end
end
end
entryを作った後にafter :createが発生する模様で、そこでカテゴリーな参照をぶち込まないとちゃんとhas_and_belongs_to_manyなリレーション関係が解決出来なかった。これはちょっと要確認
で見て分かるようにentryからはcategory1な参照は含まれていない。だけどcategory2側からはcategory1なfactoryを参照する方式で親カテゴリーの参照をぶち込んでるのでそれで利用されるっていう感じ
spec/models/entry_spec.rb
まぁテストを書く。要件的には
- FactoryGirlでentryを作る
- 作ったエントリーのカテゴリー参照を取得。結果は1件のみで結果はcategory2なCategoryクラスが入ってる (hashは異なる)
- category2なクラスから親カテゴリーを取得する
- 取得した親カテゴリーから子カテゴリー参照を取得。結果は1件のみで上記で書いてる category2なCategoryのインスタンスが入る (hashは異なる)
- 親カテゴリーから取得した子カテゴリー自体が参照するentryが最初に取得したEntryなインスタンスと同等なオブジェクトであるかをチェック
require "spec_helper"
describe Entry do
it "factory_girl test" do
# FactoryGirlでEntryを作る
entry = create(:entry)
expect(entry).not_to be_nil
expect(entry.title).to eq("test")
expect(entry.content).to eq("test")
# Entryが参照しているCategoryを取得
categories = entry.category
expect(categories.size).to eq(1)
# Entryが参照しているカテゴリーを取得。category2であるかチェック
category = categories.first
expect(category).not_to be_nil
expect(category.name).to eq("B")
# 参照しているカテゴリーの親カテゴリーを取得。category1であるかチェック
parent = category.parent_category
expect(parent).not_to be_nil
expect(parent.name).to eq("A")
expect(parent.entry.size).to eq(0)
# 親カテゴリーを参照している子カテゴリーを取得
sub_categories = parent.sub_category
expect(sub_categories.size).to eq(1)
# 親カテゴリーを参照しているカテゴリー自体がentryが参照しているカテゴリーと同一?かをチェック
sub_category = sub_categories.first
expect(sub_category).not_to be_nil
expect(sub_category).to eq(category)
# 子カテゴリーが参照しているEntryを取得
sub_category_entries = sub_category.entry
expect(sub_category_entries.size).to eq(1)
# 子カテゴリーが参照しているEntryが上記のEntryと同一?かをチェック
sub_category_entry = sub_category_entries.first
expect(sub_category_entry).not_to be_nil
expect(sub_category_entry).to eq(entry)
end
end
終わり。なかなか難しいような感じも否めないんだけど、ドキュメント読みつつやってみようかと。んまぁおさわり的にはこんなもんかなーっと