[Rspec] FactoryGirl create vs build vs build_stubbed

根據上一篇「測試效能最佳化」裡提到的一個概念

減少不必要的 DB 操作來提高測試效率

而其中做了以下幾件事

  1. 每支測試檔案,只做一次 clear DB 確保測試檔案之間不互相影響
  2. 可以使用一個數據進行測試,就不要每個 example 重複創建,減少 let and let! 大量使用實例變量
  3. 情境判斷,盡可能使用 mock 數據方式,達到你要的測試結果
  4. 使用 FactoryGirl.build orFactoryGirl.build_stubbed

前 3 點,已經熟能生巧
第 4 點,是我一直抱著 try try 看去實做
而今天偶然發現這兩個差別,做筆記分享一下

FactoryGirl

Rspec 使用這個 FactoryGirl大家應該不陌生
或許你的專案,是用基於 FactoryGirl 之上的 FactoryBot

關於 FactoryGirl.create

rails.console
1
[1]pry(main)> user = FactoryGirl.create(:user)

console

可以發現對 DB 有一次 commit,創建一筆 User 實體數據

所以你的測試第一行如果是

1
let(:user) { create(:user, rich)}

假設 user_spec.rb 有 100 個 example
進行這個測試檔案的過程,你會真實得到 100 個不同的 user。
如果你還設定在每一次的 example 做 DatabaseCleaner

spec/rails_helper.rb
1
2
3
config.after(:each) do
DatabaseCleaner.clean
end

恭喜你還會清除這 100 筆資料
等於跑一次測試,背後進行了 200 次的 DB commit

關於 FactoryGirl.build

rails.console
1
[1]pry(main)> order = FactoryGirl.build(:order)

假設你的 Factory::order 有以下兩個 association

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
factory :order do
association :user, factory: [:user, :email_confirmed, :rich]
association :offer, factory: [:sell_offer, :with_market_price]
end

factory :user do
.
.
.
trait :rich do
after(:create) do |user|
user.accounts.update_all(balance: 1000, locked: 500)
end
end
end

確實得到 order id 為 nil,且並沒有存進數據庫裡
但是…不巧的是,這裡還是有 DB commit,因為埋了一個伏筆:
代碼裡 Factory::user搭配 :rich會進行 update,也就是會 save
所以 user 還是一筆真實數據存入 DB (心裡OS: !!E@!#$@)

總結來說:

build 一個 order 會創建其相關的 association
理所當然 order.user 會是一個 id 為 nil 的數據

應用測試場景像是進行 model 層的 validation 驗證就可以使用 build

1
expect { order.valid? }.to eql(fasle)

關於 FactoryGirl.build_stubbed

rails.console
1
[1]pry(main)> order = FactoryGirl.build_stubbbed(:order)

可以發現快速的得到一個 order,也就是既有 id 也有 created_at 等等…
是一個極真的實例,但沒有任何 DB commit

但是實際查相關 association(order.user) 是完全沒有數據的
所以跟使用 FactoryGirl.build 相比,就顯而易見其差異性

如果在你的測試環節裡,是會用 association 去獲取相關真實數據的話
假設付款後,預期會同時創建一筆發票記錄,就建議別使用 build_stubbed
當然想使用複雜的 mock 技巧,那就另當別論~

結論

所以在大部分場景裡,建議如果 build 可以跑過測試,可以嘗試使用 build_stubbed,這是真的可以提高測試效率的,就在我某支測試檔案上擁有 11 個 example 儘管只跑了 8 秒,仍可以減少 4 秒,夠厲害了!
再找 build_stubbed 時,網路上查到前幾筆資料也都跟提升測試效能有關!
所以滿建議大家有機會玩玩看,親自查查相關資料佐證

Ref

Factory Bot cheatsheet:

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×