Rails 5 - RSpec с FactoryGirl выдает ошибку неверного числа аргументов - PullRequest
0 голосов
/ 25 апреля 2018

Это первый раз, когда я пишу тестовые примеры для проекта rails, использующего RSpec и FactoryGirl

Когда я запускаю тестовый пример, я получаю следующую ошибку

неправильноколичество аргументов (дано 0, ожидается 1)

Я просмотрел другие посты в стеке над потоком, и они не очень полезны в моем случае.

Что япопробовал

Я пишу тестовый пример для Модели, который называется ImportFeed, и он выглядит примерно так:

class ImportFeed < ApplicationRecord
  belongs_to :staffroom
  belongs_to :user,  optional: true   # We don't have to have a user

  validates_presence_of  :url, :feed_type
  validates :enabled,     presence: true, allow_blank: true

  def initialize(params)
    super(params)
    self.enabled = false if self.enabled.blank?
    self.default_radius = DEFAULT_RADIUS  if self.default_radius.blank?
    self.default_days = DAYS_DEFAULT if self.default_days.blank?
  end
end

Вот так выглядит мой тестовый пример

require 'rails_helper'

describe JobImporters::JoraJobImporter, '.run' do

  it 'should create an instance of ImportFeed' do
    feed = ImportFeed::new FactoryGirl.create(:import_feed, :import1)
    expect(feed).to be_a ImportFeed
  end
end

Это фабрика

FactoryGirl.define do

  factory :import_feed do

    trait :import1 do
      enabled true
      feed_type 'example'
      staffroom_id 7526
      url Faker::Internet::url
    end
  end
end

Когда я запускаю это, я получаю ошибку, упомянутую в начале этого вопроса,

Если я передаю данные втестовый пример без FactoryGirl, тогда мой тестовый пример работает и проходит, например, если я заменю

feed = ImportFeed::new FactoryGirl.create(:import_feed, :import1)

на

feed = ImportFeed::new enabled: true, staffroom_id: 7526, feed_type: 'example', url: Faker::Internet::url

тестовый пример пройден.

Я действительно будупризнателен, если кто-то может указать мне, что я здесь делаю неправильно.

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Поскольку вы переопределяете метод initialize, поэтому вы получили неожиданное исключение.

Не переопределяйте инициализацию объектов ActiveRecord ActiveRecord :: Base не всегда использует new для создания объектов,поэтому инициализация не может быть вызвана. [ссылка]

Чтобы решить вашу проблему, вы должны вместо этого установить свои атрибуты в обратном вызове

class ImportFeed < ApplicationRecord
  # ...
  after_initialize :set_my_attributes

  private

  def set_my_attributes
    self.enabled = false if self.enabled.blank?
    self.default_radius = DEFAULT_RADIUS  if self.default_radius.blank?
    self.default_days = DAYS_DEFAULT if self.default_days.blank?
  end
end

Еще одна вещь:

Вы тестируете создание экземпляра функциональности ImportFeed, поэтому вы должны либо передать параметры в методы new или create, но вы передаете ему экземпляр ImportFeed (изFactoryGirl).

Согласно документам, ActiveRecord#new принимает только Hash (аргумент по умолчанию - {}, если вы ничего не передаете).

Если вы передаете объектк нему вы получите ArgumentError исключение вместе с сообщением «При назначении атрибутов вы должны передать хеш в качестве аргумента»

def assign_attributes(new_attributes)
  if !new_attributes.respond_to?(:stringify_keys)
    raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
  end
  return if new_attributes.empty?

  attributes = new_attributes.stringify_keys
  _assign_attributes(sanitize_for_mass_assignment(attributes))
end
0 голосов
/ 25 апреля 2018

Я думаю, вы просто используете метод initialize для изменения значений в соответствии с условиями:

def initialize(params)
  super(params)
  self.enabled = false if self.enabled.blank?
  self.default_radius = DEFAULT_RADIUS  if self.default_radius.blank?
  self.default_days = DAYS_DEFAULT if self.default_days.blank?
end

Вы не должны отвергать это (мое предложение), поскольку это может сломать многие вещи. Таким образом, вместо этого вы можете изменить значения обратного вызова (before_validation, before_save, before_create, after_initialize, в зависимости от того, что вам подходит), например:

before_create :set_default_radius, if: proc { |feed| feed.default_radius.blank? }

def set_default_radius
  self.default_radius = DEFAULT_RADIUS
end

И лучший способ сделать это - использовать значение по умолчанию в самой базе данных. Вы можете определить это в миграции:

def up
  change_column :import_feeds, :default_radius, :integer, default: 0
end

def down
  change_column :import_feeds, :default_radius, :integer, default: nil
end

Таким образом, если значение не определено, оно всегда будет иметь значение по умолчанию, указанное в файле миграции.

Также вы можете прочитать несколько вопросов, связанных с этим, у которых есть несколько очень хороших ответов и объяснений:

Как переопределить «новый» метод для модели рельсов

Почему переопределение ActiveRecord :: Base.initialize неверно?

Переопределение инициализации ApplicationRecord, плохая идея?

...