Тестирование Rails с помощью rspec

У меня проблема с моим тестированием на рельсах с помощью 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 или я допустил ошибку в своих проверках и отношениях в моих обычных моделях. Кто-нибудь может мне помочь?


person Pyrmon55    schedule 14.03.2018    source источник
comment
В дочерней фабрике f.user_id должен ссылаться на существующую запись пользователя. В настоящее время это не так, что вызывает эту пустую ошибку при создании дочернего элемента. Используйте f.assocation(:user, :factory => :user) вместо строки f.user_id. Если ваш набор тестов не требует, чтобы объект Child имел связанную запись User, вы можете имитировать метод user объекта Child только для этого контекста теста, что сэкономит вам некоторые производительности.   -  person MrYoshiji    schedule 14.03.2018
comment
Кстати, FactoryGirl.create_list(:factory_name, 3) более эффективен, чем 3.times { create(:factory_name) }   -  person MrYoshiji    schedule 14.03.2018
comment
@MrYoshiji, вы должны оставить это как ответ   -  person max pleaner    schedule 15.03.2018
comment
Спасибо за помощь. Я попробовал это, как вы сказали, с заменой строки f.user_id, но я получил новую ошибку с неправильным количеством аргументов Ошибка/Ошибка: f.assocation(:user, : factory =› :user) {Faker::Number.between(1,10)} ArgumentError: неправильное количество аргументов (дано 3, ожидается 1..2)   -  person Pyrmon55    schedule 15.03.2018
comment
можно просто сказать association :user или даже просто user   -  person mr_sudaca    schedule 15.03.2018
comment
Хорошо, извините за мои глупые вопросы, но я действительно плох в 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   -  person Pyrmon55    schedule 15.03.2018


Ответы (1)


Я думаю, что было бы лучше разместить всю фабрику для вас. И я думаю, вам не нужно 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
person Vasilisa    schedule 15.03.2018
comment
Большое спасибо за вашу помощь! Я заменил эту часть в своем коде, но before { get :show, id: user.id} выдает ошибку. Можно ли показать мне, как я могу переставить первый тест? Ошибка следующая NameError: undefined local variable or method user' для #‹RSpec::ExampleGroups::UsersController::GETShow` - person Pyrmon55; 15.03.2018
comment
Спасибо за помощь! Я думаю, что у меня есть фундаментальная ошибка в моем коде. Я изменил свой код, как и ваш, и теперь я получаю сообщение об ошибке, что метод создания определен undefined method create - person Pyrmon55; 15.03.2018
comment
@Pyrmon55, измени create на FactoryGirl.create. Почему у вас есть строка require 'factory_girl_rails' в тесте? Он должен работать автоматически, если у вас есть этот гем в Gemfile. - person Vasilisa; 15.03.2018
comment
Большое спасибо за Вашу помощь! - person Pyrmon55; 15.03.2018