FactoryGirlを使ってみる

2013-06-21T00:00:00+00:00 rspec Ruby Rails

何やら色々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

終わり。なかなか難しいような感じも否めないんだけど、ドキュメント読みつつやってみようかと。んまぁおさわり的にはこんなもんかなーっと

Eclipse BIRTで参照するデータソースをJava側から変更させる方法 Jenkinsのジョブをcurlで処理する