Ruby、rspec によるファクトリーボットエラーの重複
概要
アプリでエラーが発生してしまいました。最初に RSpec と PagesController テストでテストしています。
let(:user) { create(:user, favorite_category: "Elettronica") }
エラーが発生します:
Failure/Error:
factory :user , class: User do
email { '[email protected]' }
password { 'password' }
full_name { 'a b' }
uid { '12345' }
avatar_url { 'http://example.com/avatar.png' }
role { 0 }
favorite_category { "moda" }
end
フォルダー spec/factory 内の異なるファイルに 3 つのファクトリーがあり、すべてユーザーに関連しています。
行き詰まってしまい、何が問題なのか分かりません。
私のユーザーモデル:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and
:omniauthable
devise :omniauthable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, omniauth_providers:
[:google_oauth2]
attr_accessor :current_password
has_one_attached :avatar
def avatar_thumbnail
if avatar.attached?
avatar.variant(resize: "150x150!").processed
else
"/assets/default_profile.jpg"
end
end
has_many :messages
has_many :reviews
has_many :researches
has_many :active_relationships, class_name: "Relationship",
foreign_key: "follower_id",
dependent: :destroy
has_many :following, through: :active_relationships, source:
:followed
has_many :passive_relationships, class_name: "Relationship",
foreign_key: "followed_id",
dependent: :destroy
has_many :followers, through: :passive_relationships, source:
:follower
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do
|user|
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
user.full_name = auth.info.name # assuming the user model has a
name
user.avatar_url = auth.info.image # assuming the user model has an
image
# If you are using confirmable and the provider(s) you use validate
emails,
# uncomment the line below to skip the confirmation emails.
# user.skip_confirmation!
end
end
def admin?
role == 1 # Supponiamo che tu abbia un campo 'role' nel tuo modello
User
end
def moderator?
role == 2 # Supponiamo che tu abbia un campo 'role' nel tuo modello
User
end
**strong text**
def follow(other_user)
active_relationships.create(followed_id: other_user.id)
end
# Unfollows a user.
def unfollow(other_user)
active_relationships.find_by(followed_id: other_user.id).destroy
end
# Returns true if the current user is following the other user.
def following?(other_user)
following.include?(other_user)
end
end`
ファクトリーユーザー
FactoryBot.define do
factory :user do
email { '[email protected]' }
password { 'password' }
full_name { 'John Doe' }
uid { '12345' }
avatar_url { 'http://example.com/avatar.png' }
role { 0 }
favorite_category { "Elettronica" }
end
end
ページ仕様:
require 'rails_helper'
require "./spec/factories/user.rb"
RSpec.describe PagesController, type: :controller do
let(:user) { create(:user, favorite_category: "Elettronica") }
describe "GET #home" do
it "returns a successful response" do
get :home
expect(response).to be_successful
end
it "assigns the current user" do
get :home
expect(assigns(:user)).to eq(user)
end
it "assigns search results if the user has a favorite category" do
get :home
expect(assigns(:search_results)).not_to be_nil
end
it "does not assign search results if the user has no favorite category"
do
user.update(favorite_category: "nessuna categoria")
get :home
expect(assigns(:search_results)).to be_nil
end
end
describe 'GET #search' do
it 'assigns instance variables and renders the template' do
get :search, params: {
keyword: 'lamp',
sort_order: 'PricePlusShippingLowest',
minprice: 0,
maxprice: 100,
instaexp: 1,
place: 'US',
minf: '0',
maxtime: '10'
}
expect(assigns(:users)).to be_a(ActiveRecord::Relation)
expect(assigns(:keyword)).to eq('lamp')
expect(assigns(:sort_order)).to eq('PricePlusShippingLowest')
expect(assigns(:minprice)).to eq(0)
expect(assigns(:maxprice)).to eq(100)
expect(assigns(:instaexp)).to eq(1)
expect(assigns(:place)).to eq('US')
expect(assigns(:minf)).to eq('0')
expect(assigns(:maxtime)).to eq('10')
# Add more expectations for other instance variables as needed
expect(response).to render_template(:search)
end
end
describe 'GET #search' do
it 'assigns a non-empty @search_results' do
# Stub the external service that is being called in the controller
allow_any_instance_of(Caller).to receive(:cerca).and_return([
{ 'title' => 'Item 1', 'price' => 10 }
])
get :search, params: {
keyword: 'lamp',
sort_order: 'PricePlusShippingLowest',
minprice: 0,
maxprice: 100,
instaexp: 1,
place: 'US',
minf: '0',
maxtime: '10'
}
expect(assigns(:search_results)).not_to be_nil
end
end
end
エラーは FactoryBot::DuplicateDefinitonError: 工場出荷時に登録済み:ユーザー
解決策
エラーメッセージ全体を共有しましたね。したがって、ほとんどのアプリケーションでは電子メールは一意である必要があるため、電子メール列で重複エラーが発生していると推測することしかできません。
ファクトリでは、次の行でユーザーが作成されるたびに同じ電子メール アドレスが作成されます。
email { '[email protected]' }
つまり、一度に作成できるレコードは 1 つだけです。ただし、一部のテストでは 2 人のユーザーを作成する必要があり、そのようなテストは常に失敗します。
FactoryBot を使用すると、一意である必要がある列に連続した値を作成できます。電子メールの定義を次のように変更することで、FactoryBot でシーケンスを有効にできます。
sequence :email { |n| "test-#{n}@example.com" }
これにより、メール アドレスの数字が増加することで、異なるメール アドレスを持つすべてのユーザーが生成されます: [email protected]、[email protected]、[email protected]…