RSpec編2

2021.4.20

FactoryBot

FactoryBot: テストデータの作成を手伝ってくれるgem

インスタンスメソッドを作成するメソッドはbuild  create がある。

(spec/factories/tasks.rb)

FactoryBot.define do
factory :task do
sequence(:title, "title_1")
#❶title_1やtitle_2のように連番を持つデータを定義することができる。
content { "content" }
status { :todo }
#enumで定義したところから持ってきている
deadline { 1.week.from_now }
association :user
#❷アソシエーションを設定する。
関係するuserオブジェクトも自動的に作成してくれる
end
end

sequence: unique制約のあるカラムにつける。連番を使用して重複しないデータを定義する。

sequence(:title) {|n| "title_#{n}"} #元々はこの形
sequence(:title, "title_1")

ブロックを渡さずに第二引数を渡すとループの度に、.next が呼ばれるようになっている。

.next は、Ruby自体の機能だが、String#nextは末尾を増やす機能がある。

参照

FactoryBot (旧FactoryGirl) の sequence と .next - Qiita

 
❷associationを定義することでuserの記述を省略できる
association :user

 

user = FactoryBot.create(:user)
task = FactoryBot.build(:task, user: user)
#この2行が↓この1行で済む
task = FactoryBot.build(:task)

 

(spec/model/task_spec.rb)

require 'rails_helper'

RSpec.describe Task, type: :model do
describe "validation" do
it 'is valid with all attributes' do
 
task = build(:task)
expect(task).to be_valid
expect(task.errors).to be_empty
end

it 'is invalid without title' do
task_without_title = build(:task, title: "")
expect(task_without_title).to be_invalid
expect(task_without_title.errors[:title]).to eq ["can't be blank"]
end

it 'is invalid without status' do
task_without_status = build(:task, status: nil)
expect(task_without_status).to be_invalid
expect(task_without_status.errors[:status]).to eq ["can't be blank"]
end

it 'is invalid with a duplicate title' do
task = create(:task)
task_with_duplicated_title = build(:task, title: task.title)
#❸createで作成保存したtaskのtitleを持ってきている。
expect(task_with_duplicated_title).to be_invalid
expect(task_with_duplicated_title.errors[:title]).to eq ["has already been taken"]
end

it 'is valid another title' do
task = create(:task)
task_with_another_title = build(:task, title: 'another_title')
expect(task_with_another_title).to be_valid
expect(task_with_another_title.errors).to be_empty
end
end
end

 

<ポイント>

❶(spec/rails_helper.rb)

config.include FactoryBot::Syntax::Methods

 こう記述すると、FactoryBotを省略して使用することができる。

(spec/model/task_spec.rb)

task = FactoryBot.build(:task)
task = FactoryBot.build(:task, title: "")
task = build(:task)
task_without_title = build(:task, title: "")

参照

Factory Botのメソッド利用時に、"FactoryBot."を省略できる話 - Qiita 

task_without_title や task_with_duplicated_title のようにわかりやすく定義する。

 

task = create(:task) ①
task_with_duplicated_title = build(:task, title: task.title)

taskというローカル変数をcreateで作成保存する。

 title: task.title ここの部分で、①で作成したtitleを取得して、重複データを作成している。

 

 

<エラー>

 ArgumentError:'1' is not a valid status

statusのenumを、指定したものではなく、数字で指定すると出る。

今回の場合、このように指定しているので、todo doing done のどれかをテストデータで指定する必要がある。

enum status: { todo: 0, doing: 1, done: 2 }

参照

Rspecのエラー|ArgumentError is not a valid status