factory_girlを試してみた(その2)

factory_girlの使い方第二弾です。今回は、GETTING_STARTEDに書かれていることを黙々と書いていきます。

前回はこちら

使用したバージョンなど

今回使用したバージョンは

  • factory_girl_rails 3.0.0
  • factory_girl 3.0.0

を使用しています。

データの作成方法

factory_girlでデータを作成する方法は幾つかあります。最も一般的なのは、データをデータベースに保存するもの。FactoryGirl.createを使います。

irb(main):010:0> u = FactoryGirl.create(:user)
   (0.1ms)  begin transaction
  SQL (0.7ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Fri, 04 May 2012 06:57:38 UTC +00:00], ["email", "hoge@example.com"], ["name", "User1"], ["updated_at", Fri, 04 May 2012 06:57:38 UTC +00:00]]
   (3.4ms)  commit transaction
=> #<User id: 2, name: "User1", email: "hoge@example.com", created_at: "2012-05-04 06:57:38", updated_at: "2012-05-04 06:57:38">
irb(main):011:0> 

FactoryGirl.buildはデータベースに保存しません。下の実行例では、id属性がnilになっていることに注目してください。

irb(main):001:0> FactoryGirl.build(:user)
=> #<User id: nil, name: "User1", email: "hoge@example.com", created_at: nil, updated_at: nil>
irb(main):002:0> 

FactoryGirl.attributes_forでは、設定した属性値のハッシュが返ってきます。

irb(main):005:0> FactoryGirl.attributes_for(:user)
=> {:name=>"User1", :email=>"hoge@example.com"}
irb(main):006:0> 

FactoryGirl.build_stubbedではスタブオブジェクトを作成します。スタブオブジェクトって何?と思っていたのですが、データベースに登録せず、でもid属性はきちんと登録されているもののようです。

irb(main):008:0> stub = FactoryGirl.build_stubbed(:user)
=> #<User id: 1002, name: "User1", email: "hoge@example.com", created_at: nil, updated_at: nil>
irb(main):009:0> stub.save
RuntimeError: stubbed models are not allowed to access the database
	from /Users/miyohide/.rvm/gems/ruby-1.9.2-p290@blogtest/gems/factory_girl-3.0.0/lib/factory_girl/strategy/stub.rb:39:in `save'
	from (irb):9
	from /Users/miyohide/.rvm/gems/ruby-1.9.2-p290@blogtest/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
	from /Users/miyohide/.rvm/gems/ruby-1.9.2-p290@blogtest/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
	from /Users/miyohide/.rvm/gems/ruby-1.9.2-p290@blogtest/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
	from script/rails:6:in `require'
	from script/rails:6:in `<main>'
irb(main):010:0>

スタブオブジェクトは、テストデータの作成に力を発揮しそうですね。データベースにアクセスせずに、でも本物っぽいデータがほしいっていうときとか。

オブジェクトを作成するときに、値の上書きができるようです。例えば、下の例ではemail属性を上書きしています。

irb(main):013:0> FactoryGirl.build(:user)
=> #<User id: nil, name: "User1", email: "hoge@example.com", created_at: nil, updated_at: nil>
irb(main):014:0> FactoryGirl.build(:user, email: "override@example.com")
=> #<User id: nil, name: "User1", email: "override@example.com", created_at: nil, updated_at: nil>
irb(main):015:0> 

遅延属性

英語ではLazy Attributesってあるから「遅延属性」って訳したんだけどどうもしっくり来ない。

要するに、属性を文字列で表現できず式で表現するようなものを指すようです。

例えば、こんなような定義をしているとすると、

FactoryGirl.define do
  factory :user3, :class => User do
     name "User3"
     email "user3@example.com"
     created_at { 2.days.ago }
  end
end

user3をFactoryGirlでつくるとcreated_at属性が作成した日の二日前になります。

irb(main):002:0> FactoryGirl.create(:user3)
   (0.2ms)  begin transaction
  SQL (16.7ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Wed, 02 May 2012 07:09:12 UTC +00:00], ["email", "user3@example.com"], ["name", "User3"], ["updated_at", Fri, 04 May 2012 07:09:12 UTC +00:00]]
   (2.7ms)  commit transaction
=> #<User id: 3, name: "User3", email: "user3@example.com", created_at: "2012-05-02 07:09:12", updated_at: "2012-05-04 07:09:12">
irb(main):003:0> 

連番

sequenceを使えば連番データの作成が簡単にできます。例えば、次のようなコードを書きます。

FactoryGirl.define do
  sequence(:sequence_string) { |n| "email#{n}@example.com" }

  factory :user4, :class => User do
     name { FactoryGirl.generate(:sequence_string) }
     email { "#{name}@exmaple.com" }
  end

end

すると、FactoryGirl.buildを行うたびに、email属性の@前の文字列がemail1、email2、email3と連番データとなります。

irb(main):001:0> FactoryGirl.build(:user4)
=> #<User id: nil, name: "email1@example.com", email: "email1@example.com@exmaple.com", created_at: nil, updated_at: nil>
irb(main):002:0> FactoryGirl.build(:user4)
=> #<User id: nil, name: "email2@example.com", email: "email2@example.com@exmaple.com", created_at: nil, updated_at: nil>
irb(main):003:0> FactoryGirl.build(:user4)
=> #<User id: nil, name: "email3@example.com", email: "email3@example.com@exmaple.com", created_at: nil, updated_at: nil>
irb(main):004:0> 

ユニーク属性がかかっているデータの生成に使えそうですね。

とりあえず、今日はここまで。次回は関連の書き方について書くことができたらいいな。