FactoryGirlとfixturesでテストにかかる時間を比べてみた
7 Reasons I'm Sticking With Minitest and Fixtures in Rails | Brandon Hilkert
この辺の記事にFactoryGirlよりfixturesの方が早くない? と書いてあったので、ちょっと単純なテストを200個くらい用意して、 どれくらい速くなるものかテストしてみました。
使用したのはその辺のMBA(8GB)です。
テストの実行ライブラリはMinitestの方です。
内容
- テストの内容
- 共通の準備
- fixtures側の準備
- FactoryGirl側の準備
- fixtures側の実行結果
- FactoryGIrl側の実行結果
- まとめ
テストの内容
本当にFactoryGirlで動的にデータベースにレコード用意するのがfixturesで最初からデータ置いている場合と比べて実際どの程度時間がかかるか見たいだけだったので、若干、テストコードに差はありますが、
- レコードの数を数える
- 単純にアソシエーションを使って、もう一方のレコードを呼び出す
みたいな感じです。
# fixturesを使った場合 # setupメソッドは不要 # これを下に200個くらい並べました test "time trial 01" do assert_equal 2, User.count assert_equal items(:one), users(:one).items.first end
# FactoryGirlを使った場合 def setup @user_one = create(:user_one) create(:user_two) @item_one = create(:item_one, user: @user_one) create(:item_two, user: @user_one) create(:item_three, user: @user_two) end # これを下に200個くらい並べました test "time trial 01" do assert_equal 2, User.count assert_equal @item_one, @user_one.items.first end
共通の準備
あと出しになっていますが、以下のようにUserモデルと、Userモデルと1対多の形でItemモデルを用意。
ある程度列が多いテーブルにしたかったのでUserモデル無駄に住所とか持ってます。
# app/models/user.rb class User < ActiveRecord::Base # t.string "first_name" # t.string "last_name" # t.integer "age" # t.string "postal_code" # t.string "address_1" # t.string "address_2" # t.string "address_3" # t.datetime "created_at" # t.datetime "updated_at" has_many :items end
# app/models/item.rb class Item < ActiveRecord::Base # t.string "name" # t.integer "user_id" # t.text "memo" # t.integer "category_id" # t.datetime "created_at" # t.datetime "updated_at" belongs_to :user end
fixtures側の準備
# test/test_helper.rb ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... end
test/fixtures/users.yml one: id: 1 first_name: 太朗 last_name: 田中 age: 20 postal_code: 111-1111 address_1: 東京都どこか区 address_2: そのへん町1-2-3 address_3: アパート適当456 two: id: 2 first_name: 次郎 last_name: 佐藤 age: 30 postal_code: 222-2222 address_1: 何とか県いずこ市 address_2: あのへん町3-2-1 address_3:
test/fixtures/items.yml one: id: 1 name: first user_id: 1 memo: memo category_id: 1 two: id: 2 name: second user_id: 1 memo: memomemo category_id: 1 three: id: 3 name: third user_id: 2 memo: memomemomemo category_id: 1
FactoryGirl側の準備
# test/test_helper.rb ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' class ActiveSupport::TestCase include FactoryGirl::Syntax::Methods # Add more helper methods to be used by all tests here... end
# factories/users.rb FactoryGirl.define do factory :user_one, class: User do first_name '太朗' last_name '田中' age 20 postal_code '111-1111' address_1 '東京都どこか区' address_2 'そのへん町1-2-3' address_3 'アパート適当456' end factory :user_two, class: User do first_name '次郎' last_name '佐藤' age 30 postal_code '222-2222' address_1 '何とか県いずこ市' address_2 'あのへん町3-2-1' address_3 '' end end
# factories/items.rb FactoryGirl.define do factory :item_one, class: Item do name 'first' memo 'memo' category_id 1 end factory :item_two, class: Item do name 'second' memo 'memomemo' category_id 1 end factory :item_three, class: Item do name 'third' memo 'memomemomemo' category_id 1 end end
fixtures側の実行結果
Finished in 0.511908s, 390.6953 runs/s, 781.3906 assertions/s. Finished in 0.471763s, 423.9416 runs/s, 847.8831 assertions/s. Finished in 0.509364s, 392.6468 runs/s, 785.2937 assertions/s. Finished in 0.492756s, 405.8800 runs/s, 811.7601 assertions/s. Finished in 0.509669s, 392.4114 runs/s, 784.8228 assertions/s.
FactoryGIrl側の実行結果
Finished in 2.042317s, 97.9280 runs/s, 195.8560 assertions/s. Finished in 1.973356s, 101.3502 runs/s, 202.7004 assertions/s. Finished in 2.026818s, 98.6768 runs/s, 197.3537 assertions/s. Finished in 1.966871s, 101.6844 runs/s, 203.3687 assertions/s. Finished in 1.949037s, 102.6148 runs/s, 205.2296 assertions/s.
まとめ
レコードの作成に対してFactoryGirlを使用してその都度作成するより、
fixturesを使用した方が、その都度レコードを作成/削除しなくてよかったり
テスト用にインスタンス変数を持たなくてよかったりするので、
1.5/200 ( s/test ) 速くなるというお話でした。
個人的な感想としては、最初から書くなら時間というより思っていたよりAssociationが書きやすかったためfixturesに寄せようかなと思います。
既にFactoryGirlでかなりの量のテストを書いている場合、
全部置き換えたらそれなりに速くなるかもしれないですが、
安全に簡単に置き換えられるのは、最初のいつものuserなどのレコード作成くらいな気がしていて、
そうすると100件あたり1s以下くらい? という話になるので、焼け石に水な印象でした。