# RSpec (Adding Data to Test)
### Fixtures
運作方式:使用YAML檔將資料直接塞入資料庫中,並轉換成ActiveRecord物件。(可以快速建構全域資料)
1. 資料庫中必須有相對應的欄位
2. 並不受ActiveRecord的驗證影響
3. Fixture會在測試一開始建立完成,測試完後會將過程rolled back
##### 優點
1. 運行速度快
2. 假資料會一直存在
##### 缺點
1. Fixture資料是全域的
2. 關聯性需要自己建立
3. 無法立即了解資料建立步驟
4. Fixture資料是脆弱的
---
### Factories
運作方式:
1. build(:project):回傳model instance,但並不會存進資料庫中
2. create(:project):回傳model instance,會存進資料庫中
3. attributes_for(:project):回傳物件屬性的hash值
4. build_stubbed(:project):很像build,但會給一個假的ActiveRecord ID
方法:
*_pair:使用factory建立出兩個物件 ex: create_pair(:project)
*_list:使用factory建立出多個物件 ex: create_list(:project, 5)
##### Inherited Factories
```ruby=
FactoryBot.define do
factory :task do
sequence(:title) {|n| "Task #{n}"}
end
factory :big_task, parent: :task do
size 5
end
factory :small_task, parent: :task do
size 1
end
end
```
```ruby=
FactoryBot.define do
factory :task do
sequence(:title) {|n| "Task #{n}"}
size 3
completed_at nil
end
trait :small do
size 1
end
trait :large do
size 5
end
end
```
##### Dates and Times
```ruby=
let(:runway){create(:proect, name: "Project Runway", start_date: "2018-01-20")}
let(:greenlight){create(:proect, name: "Project Greenlight", start_date: "2018-02-24")}
let(:gutenberg){create(:proect, name: "Project Gutenberg", start_date: "2018-01-31")}
it "finds recently started projects" do
actual = Project.find_recently_started(6.months)
expect(actual.size).to eq(3)
end
```
六個月後測試就過不了
解決方法:
1. Relative Dates
```ruby=
let(:runway){create(:proect, name: "Project Runway", start_date: 1.week.ago)}
let(:greenlight){create(:proect, name: "Project Greenlight", start_date: 1.month.ago)}
let(:gutenberg){create(:proect, name: "Project Gutenberg", start_date: 1.day.ago)}
it "finds recently started projects" do
actual = Project.find_recently_started(6.months)
expect(actual.size).to eq(3)
end
```
2. Stubbing time
ActiveSupport::Testing::TimeHelpers#travel
ActiveSupport::Testing::TimeHelpers#travel_to
```ruby=
#travel_to
it "finds recently started projects" do
travel_to(Date.parse("2018-02-10"))
actual = Project.find_recently_started(6.months)
expect(actual.size).to eq(3)
end
```
```ruby=
#travel
it "knows if the project is over" do
p = Project.new(:start_date => Date.today, :end_date = Date.today + 8.weeks)
expect(p).not_to be_complete
teavel(10.weeks)
expect(p).to be_complete
end
```