factory girlを使ってみようと思う

以前から試してみたかったfactory girl。
こないだ試した twitter-auth at master のテストで使われていたので、これを機にinstallしてみた。
(他にもfakewebやらremarkable_railsなど、いろいろ気になるのが使われてる。)
名前もなんかいいよね。girlって付くと。


thoughtbot's factory_girl at master - GitHub

参考

has_many throughでの例が非常に分かりやくて参考になります。
has_manyなフィクスチャを書くのに疲れたらFactory Girlがオススメ! - func09

バージョン

readmeよく見たらいろいろバージョンがあるらしい。
現時点では下記のよう。
(あと、いろいろforkされててfactory_boyっつーのもあるらしい。気になる)

factorygirl1.3.x(stable version for Rails3.0)

thoughtbot's factory_girl at 1.3.x - GitHub

factorygirl1.2.4(for Rails2.x)

thoughtbot's factory_girl at v1.2.4 - GitHub
(なんか1.2.5もあるみたいだが、、、github上でversionの差分確認ってできんのだろうか?)


今回は

とりあえずRails2.3系のプロジェクトで使いたいというのもあるので
1.2.4を試す。感触よければ、あとで1.3.xも試す。

install

$ gem install factory_girl -v=1.2.4 --no-ri --no-rdoc

設定

  config.gem "factory_girl", :version => '1.2.4', :source  => "http://gemcutter.com"

readmeには、enviroment.rbって書いてるけど、config/environments/test.rbの方がいいかも。


書き方

下記ファイルにfactory情報(テストデータ)を書くとtest時に使えるようになります。
まぁ、モデル毎に定義したい場合は、factories/*.rb って感じですよ。

  test/factories.rb
  spec/factories.rb
  test/factories/*.rb
  spec/factories/*.rb
基本
  # adminって名前でUser classのデータ定義をします
  Factory.define :admin, :class => User do |u|
    u.first_name 'Admin'
    u.last_name  'User'
    u.admin true
  end

  # class名を文字列で指定してもok
  # Factory.define :admin, :class => 'user' do |u|
  #
  # また、userって名前にすると(class名と一緒だと)classオプションは省略できます
  # Factory.define :user do |u|
関連を書くのが便利

これ肝だと思うんだけど、readmeに詳細が無い。
User:Blog 1対多の関係(has_many)だとすると
UserにBlogを複数持っているという関連がFactoryにすんなり書ける。
(Fixtureより随分分かりやすい)

  #User
  Factory.define :hoge, :class => User do |u|
    u.first_name 'hoge'
    u.last_name  'fuga'
    u.admin true
    u.blogs{[Factory(:first),Factory(:latest)]}
  end

  #Blog
  Factory.define :first, :class => Blog do |b|
    b.title 'hogehoge'
    b.description  'fugafuga'
  end
  Factory.define :latest, :class => Blog do |b|
    b.title 'mogumogu'
    b.description  'munyamunya'
  end


readmeには下記のような書き方が紹介されている。

  Factory.define :post do |p|
    # ...
    p.author {|author| author.association(:user, :last_name => 'Writely') }
  end

主な使い方

  # Returns a User instance that's not saved
  # save前。user.save などが可能。user.new_record? # => true となる
  user = Factory.build(:user)


  # Returns a saved User instance
  # save後。
  user = Factory.create(:user)

  # Same as Factory.create :user:
  # shortcut
  # 基本はコレかな。
  # default_strategyオプションで、shortcutの動作を変えれるみたいだが、あんまり使わなさそう
  user = Factory(:user)


  # Returns a hash of attributes that can be used to build a User instance:
  # hashが返ります。
  #{:name=>"bob",
  # :pages=>
  #  [#<Page id: 1, title: "Google", url: "http://www.google.com/", bookmark_id: nil, created_at: "2010-10-20 16:35:20", updated_at: "2010-10-20 16:35:20">,
  #    <Page id: 2, title: "Yahoo!", url: "http://www.yahoo.com/", bookmark_id: nil, created_at: "2010-10-20 16:35:20", updated_at: "2010-10-20 16:35:20">]}
  attrs = Factory.attributes_for(:user)

  # Returns an object with all defined attributes stubbed out:
  # ぱっと見よく分からなかったが、実行してみると
  # idを仮で返してくれる。(つまりstub。まんまだけど)
  # <User id: 1001, name: "bob", bookmark_id: nil, created_at: nil, updated_at: nil>
  stub = Factory.stub(:user)

sequence

は便利かな。nextで連番が使用可能。

  # Defines a new sequence
  Factory.sequence :email do |n|
    "person#{n}@example.com"
  end

  Factory.next :email
  # => "person1@example.com"

  Factory.next :email
  # => "person2@example.com"

あとは

Callbacks(after_build, after_crate, after_stub)やら
Alternate Syntaxesっつー機能もあるようだ。
まだよく分かってない。


とりあえず、もりもりテスト書いていこう。

おまけ

fixtureの代わりとしては、とりあえずダントツのようです。

The Ruby Toolbox Search