У меня проблема с тестированием в рельсах с помощью rspec. В общем, у меня есть структура между 4 моделями, но пока я пытаюсь решить свое тестирование для двух из них. Я использую faker и FactoryGirl, и у меня есть следующие фабрики:
require 'faker'
FactoryGirl.define do
factory :user do |f|
f.name { Faker::Name}
f.email { Faker::Internet.email}
f.password {Faker::Internet.password}
f.role {"Kindergarten"}
end
end
require 'faker'
FactoryGirl.define do
factory :child do |f|
f.name { Faker::Name}
f.city { Faker::Address.city}
f.postalcode {Faker::Number.between(30000,35000)}
f.streed {Faker::Address.street_name}
f.add_number {Faker::Address.secondary_address}
f.disability { Faker::Boolean.boolean}
f.halal { Faker::Boolean.boolean}
f.koscha {Faker::Boolean.boolean}
f.vegetarian {Faker::Boolean.boolean}
f.vegan {Faker::Boolean.boolean}
f.allday { Faker::Boolean.boolean}
f.gender { Faker::Number.between(0,1)}
f.user_id {Faker::Number.between(1,10)}
end
end
и мой тест контроллера выглядит так
require 'rails_helper'
require 'factory_girl_rails'
describe UsersController do
before do
3.times { FactoryGirl.create(:child)}
end
describe "GET #show" do
let(:user) { FactoryGirl.create(:user) }
before { get :show, id: user.id}
it "assigns the requested user to @user" do
assigns(:user).should eq user
end
it "renders the :show template"
end
describe "GET #new" do
let(:user) { FactoryGirl.create(:user) }
it "assigns a new User to @user" do
get :new, id: user.id
assigns(:user).should be_a_new(User)
end
it "renders the :new template"
end
end
Когда я пытаюсь запустить тест, я получаю это сообщение об ошибке
UsersController GET #new assigns a new User to @user
Failure/Error: 3.times { FactoryGirl.create(:child)}
ActiveRecord::RecordInvalid:
Validation failed: User can't be blank
Мои отношения и проверки в моделях следующие
class Child < ApplicationRecord
has_many :relations, :dependent => :destroy
accepts_nested_attributes_for :relations
belongs_to :user
validates :user, presence: true
validates :name, presence: true, length: { maximum: 50 }
validates :city, presence: true, :on => :create
validates :postalcode, presence: true, numericality: true
validates :streed, presence: true
validates :add_number, presence: true
validates :disability, inclusion: { in: [true, false] }
validates :halal, inclusion: { in: [true, false] }
validates :koscha, inclusion: { in: [true, false] }
validates :vegetarian, inclusion: { in: [true, false] }
validates :vegan, inclusion: { in: [true, false] }
validates :allday, inclusion: { in: [true, false] }
validates :gender, presence: true
end
class User < ApplicationRecord
attr_accessor :remember_token, :activation_token, :reset_token
has_many :children, dependent: :destroy
has_many :kindergartens, dependent: :destroy
has_many :relations, dependent: :destroy
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :role, presence: true
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
end
Моя проблема в том, что я не уверен, есть ли ошибка в моем коде rspec или я допустил ошибку в своих проверках и отношениях в моих обычных моделях. Кто-нибудь может мне помочь?
Кстати, FactoryGirl.create_list(:factory_name, 3) более эффективен, чем 3.times { create(:factory_name) }
@MrYoshiji, оставь это как ann annswer
Спасибо за помощь. Я пробовал, как вы сказали, с заменой строки f.user_id, но у меня появилась новая ошибка с неправильным количеством аргументов Сбой / ошибка: f.assocation (: user,: factory =>: user) {Faker :: Number.between (1,10)} ArgumentError: неправильное количество аргументов (дано 3, ожидается 1..2)
вы можете просто сказать association :user или даже просто user
Хорошо, извините за мои глупые вопросы, но я действительно плохо разбираюсь в rspec ... Я переписал свой f.user_id на f.association(:user, :factory => :user) {Faker::Number.between(1,10)}, но мой тест не работает, потому что теперь есть проблемы с кодом в тесте. Я изменил, чтобы изменить деталь id: user.id, но получаю ошибку Failure/Error: before { get :show, id: user.id} ArgumentError: unknown keyword: id





Думаю, лучше бы вам всю фабрику выложить. И я думаю, вам не нужен require faker, если он у вас есть в Gemfile.
FactoryGirl.define do
factory :child do
name { Faker::Name}
city { Faker::Address.city}
postalcode {Faker::Number.between(30000,35000)}
streed {Faker::Address.street_name}
add_number {Faker::Address.secondary_address}
disability { Faker::Boolean.boolean}
halal { Faker::Boolean.boolean}
koscha {Faker::Boolean.boolean}
vegetarian {Faker::Boolean.boolean}
vegan {Faker::Boolean.boolean}
allday { Faker::Boolean.boolean}
gender { Faker::Number.between(0,1)}
user
end
end
Внутренние спецификации, когда вам нужно создать дочерний элемент для конкретного пользователя:
let(:current_user) { create :user }
let(:child) { create :child, user: current_user }
Попробуйте изменить спецификацию вашего контроллера:
describe UsersController do
let(:user) { create(:user) }
describe "GET #show" do
before { get :show, params: { id: user.id } }
it "assigns the requested user to @user" do
assigns(:user).should eq user
end
it "renders the :show template"
it { expect(response).to have_http_status 200 }
end
describe "GET #new" do
before { get :new }
it "assigns a new User to @user" do
assigns(:user).should be_a_new(User)
end
it "renders the :new template"
end
end
Большое спасибо за вашу помощь! Я заменил эту часть в своем коде, но before { get :show, id: user.id} выдает ошибку. Можно мне показать, как я могу переставить первый тест? Ошибка следующая: NameError: undefined local variable or method user 'для # <RSpec :: ExampleGroups :: UsersController :: GETShow`
Спасибо за помощь! Я думаю, что в моем коде есть фундаментальная ошибка. Я изменил свой код, как ваш, и теперь получаю сообщение об ошибке, что метод create isn не определен undefined method create
@ Pyrmon55, замените create на FactoryGirl.create. Почему у вас в тесте линия require 'factory_girl_rails'? Он должен работать автоматически, если у вас есть этот драгоценный камень в Gemfile
Большое спасибо за Вашу помощь!
В дочерней фабрике
f.user_idдолжен ссылаться на существующую запись пользователя. В настоящее время это не так, что вызывает эту пустую ошибку при создании дочернего объекта. Используйтеf.assocation(:user, :factory => :user)вместо линииf.user_id. Если ваш набор тестов не требует, чтобы объектChildимел связанную записьUser, вы можете смоделировать методuserдляChildтолько для этого контекста теста, сэкономив вам некоторые характеристики