はじめに
ポートフォリオに実際に実装したmodel specの部分です。
テストコードについては勉強したけどテストコードを実際に書く時にどんなことをテストすればいいか分からないと思ったのでそういった人の参考になれば嬉しいです。
テストしたのはログイン、CRUD、いいね機能部分です。
User
validationのformatで指定している正規表現は、メールアドレスの形になっているのかを表しています。
Railsチュートリアルに載ってたのをまんまコピペしてきただけですが‥
app/models/user.rb
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.freeze
validates :email, presence: true, uniqueness: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
spec/factories/user.rb
FactoryBot.define do
factory :user do
email { Faker::Internet.email }
password { 'password' }
end
end
spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
describe "正常系の機能" do
context "正しく入力さている場合" do
let(:user) { build(:user) }
it "保存できる" do
expect(user.valid?).to eq true
end
end
end
describe "バリデーション" do
subject { user.valid? }
context "email が空のとき" do
let(:user) { build(:user, email: "") }
it "保存できない" do
expect(subject).to eq false
expect(user.errors.messages[:email]).to include "を入力してください"
end
end
context "email が256文字以上のとき" do
let(:user) { build(:user, email: "a" * 256) }
it "保存できない" do
expect(subject).to eq false
expect(user.errors.messages[:email]).to include "は255文字以内で入力してください"
end
end
context "email がすでに存在するとき" do
before { create(:user, email: "test@example.com") }
let(:user) { build(:user, email: "test@example.com") }
it "保存できない" do
expect(subject).to eq false
expect(user.errors.messages[:email]).to include "はすでに存在します"
end
end
context "email が アルファベット・英数字 のみのとき" do
let(:user) { build(:user, email: Faker::Lorem.characters(number: 16)) }
it "保存できない" do
expect(subject).to eq false
expect(user.errors.messages[:email]).to include "は不正な値です"
end
end
end
end
factory_botについて
factory_botですが、呼び出す時に以下のように特定のカラムに対してダミーデータの書き換えが可能です。
let(:user) { build(:user, email: "") }
便利でよく使うので覚えておきましょう!
自分も実装するまで知らなかった 笑
Event
Event部分は定番の投稿部分です!
day_after_today
はイベント開催日を今日より前には指定できなくする制限です。
app/models/event.rb
validates :name, presence: true, length: { minimum: 2, maximum: 50 }
validates :text, presence: true
validates :store, length: { minimum: 2, maximum: 50 }
validates :address, length: { minimum: 2, maximum: 50 }
validate :day_after_today
def day_after_today
errors.add(:base, '開催日程は今日より前の日は指定できません') if start_time.present? && start_time < Date.today
end
spec/factories/event.rb
FactoryBot.define do
factory :event do
name { Faker::Lorem.characters(number: 10) }
text { Faker::Lorem.characters(number: 100) }
store { Faker::Lorem.characters(number: 20) }
address { Faker::Lorem.characters(number: 20) }
start_time { Date.today }
category_id { 1 }
user
end
end
spec/models/event_spec.rb
require 'rails_helper'
RSpec.describe Event, type: :model do
let(:user) { build(:user) }
describe "正常系の機能" do
context "正しく入力さている場合" do
let(:event) { build(:event) }
it "保存できる" do
expect(event.valid?).to eq true
end
end
end
describe "バリデーション" do
subject { event.valid? }
context "name が空の場合" do
let(:event) { build(:event, name: "") }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:name]).to include "を入力してください"
end
end
context "name が2文字以下の場合" do
let(:event) { build(:event, name: Faker::Lorem.characters(number: 1) ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:name]).to include "は2文字以上で入力してください"
end
end
context "name が50文字以上の場合" do
let(:event) { build(:event, name: Faker::Lorem.characters(number: 51) ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:name]).to include "は50文字以内で入力してください"
end
end
context "text が空の場合" do
let(:event) { build(:event, text: "") }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:text]).to include "を入力してください"
end
end
context "store が2文字以下の場合" do
let(:event) { build(:event, store: Faker::Lorem.characters(number: 1) ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:store]).to include "は2文字以上で入力してください"
end
end
context "store が50文字以上の場合" do
let(:event) { build(:event, store: Faker::Lorem.characters(number: 51) ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:store]).to include "は50文字以内で入力してください"
end
end
context "address が2文字以下の場合" do
let(:event) { build(:event, address: Faker::Lorem.characters(number: 1) ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:address]).to include "は2文字以上で入力してください"
end
end
context "address が50文字以上の場合" do
let(:event) { build(:event, address: Faker::Lorem.characters(number: 51) ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:address]).to include "は50文字以内で入力してください"
end
end
context "start_time が今日より前の日付の場合" do
let(:event) { build(:event, start_time: "2000-07-30" ) }
it "保存できない" do
expect(subject).to eq false
expect(event.errors.messages[:base]).to include "開催日程は今日より前の日は指定できません"
end
end
end
end
Clip
Clipは多対多のいわゆるいいね機能と同じ機能です。
ここではIDが存在しないと保存できないっていうテストをしています。
app/models/clip.rb
validates :user_id, presence: true, uniqueness: { scope: :event_id }
validates :event_id, presence: true
spec/factories/clip.rb
FactoryBot.define do
factory :clip do
user_id { FactoryBot.create(:user).id }
event_id { FactoryBot.create(:event).id }
end
end
spec/models/clip_spec.rb
require 'rails_helper'
RSpec.describe Clip, type: :model do
subject { clip.valid? }
describe "正常の機能" do
context "データが条件を満たす場合" do
let(:clip) { build(:clip) }
it "保存できる" do
expect(subject).to eq true
end
end
end
describe "バリデーション" do
context "user_idが存在しない場合" do
let(:clip) { build(:join, user_id: nil) }
it "保存できない" do
expect(subject).to eq false
expect(clip.errors.messages[:user]).to include "を入力してください"
end
end
context "event_idが存在しない場合" do
let(:clip) { build(:join, event_id: nil) }
it "保存できない" do
expect(subject).to eq false
expect(clip.errors.messages[:event]).to include "を入力してください"
end
end
context "user_idが既に存在する場合" do
let(:user) { create(:user) }
let(:event) { create(:event, user_id: user.id) }
before do
create(:clip, user_id: user.id, event_id: event.id)
end
let(:clip) { build(:clip, user_id: user.id, event_id: event.id) }
it "保存できない" do
expect(subject).to eq false
expect(clip.errors.messages[:user_id]).to include "はすでに存在します"
end
end
end
end
以上です!
実際にコードレビューもしてもらったので問題ないはず!
テストはこんな感じで書くんだなーっていう雰囲気が伝われば嬉しいです!
次はrequest spec!