Rails 5 Test Prescriptions 第6章Adding Data to Tests
bcreate the data quickly and easily。考慮測試運行的速度。
fixtures and factories.以及下章討論的test doubles,還有原生的create創建的,沒有一個方案可以解決所有情景。
Fxitures
如果想使用固件。RSpec目錄是spec/fixtures/projects.yml。 Mini test的目錄是test/fixtures/
runway:
name: Project Runway
due_date: 2016-12-18
projects(:runway)
名字可以描述用途,比如projects(:project_with_no_due_date)
Fixture接受ERB files.可以使用<%= %> ,不建議使用使用循環。
Loading Fixture Data
在測試開始時固件會一次性加載,使用事物transaction,因此在測試結束時會回滾。回歸初始狀態。
固件運行速度塊。固件是全局性的數據 儲存在database中。
固件是分散的,不適合管理connections,關聯數據。
總之,固件不適合在復雜的程序使用。
Factories factory_bot
gem ‘factory_bot_rails‘ 目錄spec/factories/
在spec的一個文件中配置:
RSpec.configure do |config|每次用create方法無需加上FactoryBot前綴了。
詳細用法:本博客: https://www.cnblogs.com/chentianwei/p/9047596.html
Factory_bot假定class的名字就是你定義的名字。如果要自定義類,需要指定類名。
FactoryBot.define do factory :project, class: Project do name "Project Runway" due_date {Date.today - rand(50)} #隨機時間。50天內的。Basic Factory Creation
build(:project): 非關聯對象可以使用。
create(:project):別用,除非對象之間有關聯,必須存入數據庫。因為會讓測試減慢。
attributes_for(:project) 需要對hash屬性進行驗證時,使用,一般見於controller test。
build_stubbed(:project) Unlike build, it assigns a fake ActiveRecord ID to the model and stubs out database-interaction methods (like save) such that the test raises an exception if they are called.
Prescription: 盡量使用這個方法,有build的一切功能,還能生成一個假Rails id,有了這個就能建立belongs_to 關聯,同時不會被存入數據庫。
*_pair and *_list 兩個方法,沒看。
Associations and Factories
FactoryBot.define do factory :task do title "Thing to do" size 1 completed_at nil project#這樣調用task = create(:task)就會自動調用task.project = create(:project)
endend
也可以單獨建立關聯:
task = FactoryBot.create(:task, project: Project.new)
如果已經在factory definition中建立了關聯,同時不想在測試中有value,設置nil
task = FactoryBot.create(:task, project: nil).
如果關聯名字不匹配factory name或者你想指定關聯對象的默認的屬性:
在factory definition 中使用association方法
association :doer, factory: :user, name: "Task Doer"
只有保存在數據庫中,對象有了id才能關聯。但可以使用build_stubbed來創建不保存的對象
或者使用create方法。
作者建議在定義中建立關聯,但不設置屬性。屬性在測試中設置。
association :user
更直接的 user
Managing Duplication in Factories
對於2個以上的factories, Factory_bot可以做到管理。文檔裏面有許多技巧,但以下3個最常用。
sequence方法
對於需要unique values 的屬性,如登陸,或電子郵件。可以使用sequence方法。
sequence(:title) { |n| "Task #{n}"}
起始n是1. 每被調用一次n加1。
inherited factories 繼承的特性
FactoryBot.define do factory :task do sequence(:title){ |n| "Task #{n}"} #可以嵌套進來 factory :big_task do size 5 end factory :small_task do size 1 end end#或者加上parent: :task factory :middle_task, parent: :task do size 3 endend
trait方法
trait
優點:設置一個有意義的名字,方便理解
缺點:需要額外的輸入和增加了復雜度。
用於指定一批的特定的屬性,一個省事的方法。
這個方法放在factory :task的塊中,就可以被task使用。
FactoryBot.define dofactory :task do title "Thing to do" size 1 completed_at nil trait :small do size 1 end
#繼承一個對象,並使用了trait
factory :trivial do small end endend調用: let(:task){build(:task, :smal)}
Preventing Factory Abuse
創建最小數量的數據剛好夠測試用就可以了。
Dates and Times
測試歷法邏輯,讓人頭疼,但可以使用a couple of things 來簡化時間邏輯這個野獸 .
Using Relative Dates
Date.today 和 1.day.ago, 2.months.ago, 2.weeks.ago結合使用。
如在
factory :project do
start_date {1.week.ago}
end
gutenberg:
start_date: <%= 1.day.ago %>
缺點就是如果某個時間是已知的,就沒辦法使用相對時間了。
Stubbing Time
把時間凍結!!!用a stub來明確指定時間。
需要用到Raisl helper方法。
ActiveSupport::Testing::TimeHelpers#travel
Changes current time to the time in the future or in the past by a given time difference by stubbing Time.now
, Date.today
, and DateTime.now
. The stubs are automatically removed at the end of the test.
Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
travel 1.day do
User.create.created_at # => Sun, 10 Nov 2013 15:34:49 EST -05:00
end
Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
如 travel 1.month, 接受一段時間作為參數。 一個整數。
ActiveSupport::Testing::TimeHelpers#travel_to
travel_to(date_or_time)接受1個固定的時間/日記,作為參數。
pasting
Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
end
Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
trave_back 重置時間回到初始狀態。
可以在這兩個參數的塊內,進行斷言,或者期望expect.
Comparing Time
Ruby有三個獨立的時間類。Time, Date, DateTime.
因此Date的實例和DateTime的實例是無法比較和加減的
使用to_s(:db)進行轉化。
1.day.ago.to_date.to_s(:db) => "2018-05-25" 1.day.ago.to_date => Fri, 25 May 2018
Setting Rails Timestamps
可以使用created_at 在預制件,或者固件中。
Rails 5 Test Prescriptions 第6章Adding Data to Tests