iT邦幫忙

2021 iThome 鐵人賽

DAY 9
0
自我挑戰組

Rails測試寫起乃!!!系列 第 9

Day09 測試寫起乃-FactoryBot(1)

在測試時常會需要建立假資料以供測試使用,就可以安裝 FactoryBot 來建立資料

安裝 FactoryBot

指令 gem "factory_bot_rails" 並且 bundle install

官方文件-FactoryBot Getting Started

基本語法就是使用 FactoryBot.create(:user) 就可以建立出一筆User了

可以在新增 spec/support/factory_bot.rb 並且把以下指令放在檔案內,在 rspec 時就可以省略FactoryBot,直接 create(:user) 即可,那你也可以直接放在 rails_helper.rb 也同樣有效。

#spec/support/factory_bot.rb or rails_helper.rb

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

建立第一筆資料

看文件只要將 file 依照以下位置擺放都會自動吃到

test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb

接下來新增一個 spec/factories/users.rb

# This will guess the User class
FactoryBot.define do
  factory :user do
    name { "CK" }
    email  { "ck@gmail.com" }
  end
end

factory會從 class 去搜尋是否有 User 這個 class,沒有的話他會提醒你他找不到,裡頭就可以直接填寫 model 欄位右方 block 裡面就是放內容。

我們到 console 試試是否能夠建立出來吧!

# rails console -e test
2.6.6 :001 > FactoryBot.create(:user)
D, [2021-09-09T19:06:57.193940 #42363] DEBUG -- :    (1.7ms)  SELECT sqlite_version(*)
D, [2021-09-09T19:06:57.230186 #42363] DEBUG -- :   TRANSACTION (0.2ms)  begin transaction
D, [2021-09-09T19:06:57.231393 #42363] DEBUG -- :   User Exists? (0.6ms)  SELECT 1 AS one FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "ck"], ["LIMIT", 1]]
D, [2021-09-09T19:06:57.234314 #42363] DEBUG -- :   User Create (0.8ms)  INSERT INTO "users" ("created_at", "updated_at", "name", "email") VALUES (?, ?, ?, ?)  [["created_at", "2021-09-09 11:06:57.231907"], ["updated_at", "2021-09-09 11:06:57.231907"], ["name", "ck"], ["email", "ck@gmail.com"]]
D, [2021-09-09T19:06:57.235901 #42363] DEBUG -- :   TRANSACTION (0.9ms)  commit transaction
 => #<User id: 1, created_at: "2021-09-09 11:06:57.231907000 +0000", updated_at: "2021-09-09 11:06:57.231907000 +0000", name: "ck", email: "ck@gmail.com", phone: nil>

所以就可以把原本的測試改寫為

# user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'validations' do
    it { is_expected.to validate_presence_of(:name) }
  end

  describe 'count user' do
    let(:user) { create(:user) } # 此處使用factorybot 建立
    it 'no user' do
      expect(User.count).to eq(0)
    end

    it 'one user' do
      user
      expect(User.count).to eq(1)
    end
  end
end

但這邊會遇到一個問題,如果我想一次建立兩筆user但user名稱又不能重複?

如果使用目前的user建立出來兩筆資料 name 與 email 都會相同,該如何改呢?

sequence

# This will guess the User class
FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "ck-#{n}"}
    sequence(:email) { |n| "ck-#{n}@gmail.com" }
  end
end
#rails console -e test
 => #<User id: 1, created_at: "2021-09-09 11:18:41.436395000 +0000", updated_at: "2021-09-09 11:18:41.436395000 +0000", name: "ck-1", email: "ck-1@gmail.com", phone: nil>
=> #<User id: 2, created_at: "2021-09-09 11:19:17.282845000 +0000", updated_at: "2021-09-09 11:19:17.282845000 +0000", name: "ck-2", email: "ck-2@gmail.com", phone: nil>

可以看到名稱多編號這樣一來就不會重複!

那你也可以使用 create_list(:factory_name,count) 一次建立兩筆

#rails console -e test
2.6.6 :003 > FactoryBot.create_list(:user,2)
 => [#<User id: 3, created_at: "2021-09-09 11:20:10.871562000 +0000", updated_at: "2021-09-09 11:20:10.871562000 +0000", name: "ck-3", email: "ck-3@gmail.com", phone: nil>,
 #<User id: 4, created_at: "2021-09-09 11:20:10.877319000 +0000", updated_at: "2021-09-09 11:20:10.877319000 +0000", name: "ck-4", email: "ck-4@gmail.com", phone: nil>]

覆蓋屬性

在 factory 後方一樣可以輸入 attribute,覆蓋掉原本預設的資料。

#rails console -e test
2.6.6 :005 > FactoryBot.create(:user, name:'ck_over',email: 'ck_over@gmailc.om')
 => #<User id: 5, created_at: "2021-09-09 11:22:43.618214000 +0000", updated_at: "2021-09-09 11:22:43.618214000 +0000", name: "ck_over", email: "ck_over@gmailc.om", phone: nil>

基本上使用這些就可以解決大部分建立資料的問題,明天我們就可以來講解,traitparentassociationalias


上一篇
Day08 測試寫起乃-關於測試如何清除test db資料? & 安裝 Database Cleaner
下一篇
Day10 測試寫起乃-FactoryBot(2)
系列文
Rails測試寫起乃!!!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言