--- title: FactoryBot筆記 description: 語法 robots: noindex, nofollow lang: zh-tw dir: ltr breaks: true tags: FactoryBot disqus: hackmd --- # 基礎應用 [基礎篇](https://devhints.io/factory_bot) [Github FactoryBot Getting Started](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md) ## Setting Rspec 就不用再輸入`FactoryBot`直接`create(:xxx)`即可 ```ruby= RSpec.configure do |config| config.include FactoryBot::Syntax::Methods end ``` Cucumber ```ruby= # env.rb (Rails example location - RAILS_ROOT/features/support/env.rb) World(FactoryBot::Syntax::Methods) ``` 將 Factory 設定在以下路徑 `FactoryBot.find_definitions` 會自動找到此路徑加載 Factory ```ruby= test/factories.rb spec/factories.rb test/factories/*.rb spec/factories/*.rb ``` ## 基礎 使用範例: ```ruby= # This will guess the User class FactoryBot.define do factory :user do first_name { "John" } last_name { "Doe" } admin { false } end end ``` 上述所說會去猜測是否有 User 這個 class 然後依照你 Model欄位來寫attributes 最後幫你建出一筆 user。花括弧可省略 ```ruby= # This will use the User class (otherwise Admin would have been guessed) factory :admin, class: "User" ``` 意思是你也可以替factory指定其他名稱但必須指定他屬於哪個class ### 建立bot factory_bot supports several different build strategies: build, create, attributes_for and build_stubbed: ```ruby= # Returns a User instance that's not saved user = build(:user) # Returns a saved User instance user = create(:user) # Returns a hash of attributes that can be used to build a User instance attrs = attributes_for(:user) # {name: 'CK', phone: '123'} # Returns an object with all defined attributes stubbed out stub = build_stubbed(:user) # Passing a block to any of the methods above will yield the return object create(:user) do |user| user.posts.create(attributes_for(:post)) end ``` create => 真的寫進db build => 還沒save 且 id為 nil build_stubbed => stub的概念創建一個假的實體而且還有id 如果不懂build、create、build_stubbed的可以看看這篇 [FactoryGirl create vs build vs build_stubbed](https://blog.gmifly.tw/2019/04/14/Rspec-FactoryGirl-vs-create-vs-build-vs-build-stubbed/) [attributes_for看不懂看這篇](https://stackoverflow.com/questions/13150272/meaning-for-attributes-for-in-factorygirl-and-rspec-testing) ### Aliases 不常使用,用法其實就是association的概念只是縮寫 ```ruby= factory :user, aliases: [:author, :commenter] do first_name { "John" } last_name { "Doe" } date_of_birth { 18.years.ago } end factory :post do # 寫法等同於 association :author, factory: :user # 寫法等同於 association :user author title { "How to read a book effectively" } body { "There are five steps involved." } end ``` 不過這邊不推薦使用`association`因為他會在你建立這筆bot時也將有關聯的bot一同建立出來, 建議使用 `trait` ### Dependent Attributes 可以定義動態區塊在建立bot時在指定值 ```ruby= factory :user do first_name { "Joe" } last_name { "Blow" } email { "#{first_name}.#{last_name}@example.com".downcase } end create(:user, last_name: "Doe").email # => "joe.doe@example.com" ``` ### Transient(目前搞不出來,測試中) 不常使用,可以定義不是attributes的值拿來判斷或是存放值 ```ruby= factory :user do transient do rockstar { true } end name { "John Doe#{" - Rockstar" if rockstar}" } end create(:user).name #=> "John Doe - ROCKSTAR" create(:user, rockstar: false).name #=> "John Doe" ``` ```ruby= factory :car do transient do # capitalize is not an attribute of the car capitalize false end name { "Jacky" } purchase_price { 1000 } model { "Honda" } after(:create) do |car, evaluator| car.name.upcase! if evaluator.capitalize end end car = FactoryGirl.create(:car, capitalize: true) car.name # => "JACKY" ``` [這邊有更詳細的講解](https://stackoverflow.com/questions/38573131/what-is-the-purpose-of-a-transient-do-block-in-factorybot-factories) ## 其他相關文件 [FactoryBot在4.11之後刪除所謂的靜態屬性](https://thoughtbot.com/blog/deprecating-static-attributes-in-factory_bot-4-11)(目前我還沒實測出來)