Rails 5 - RSpec 与 FactoryGirl 给出错误参数数量错误

Rails 5 - RSpec with FactoryGirl giving error wrong number of arguments

这是我第一次在使用 RSpec 和 FactoryGirl

的 rails 项目上编写测试用例

当我 运行 测试用例时,出现以下错误

wrong number of arguments (given 0, expected 1)

我浏览了 stack over flow 上的其他帖子,它们对我的情况没有太大帮助。

我试过的

我正在一个名为 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

测试用例通过。

如果有人能指出我这里做错了什么,我将不胜感激。

我认为您只是使用 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

因此,如果未定义该值,它将始终设置为迁移文件中提到的默认值。

你也可能读过几个与此相关的问题,其中有一些很好的答案和解释:

How to override "new" method for a rails model

Why is overriding ActiveRecord::Base.initialize wrong?

因为你重写了initialize方法,所以你得到了意外的异常。

Don't override initialize on ActiveRecord objects ActiveRecord::Base doesn't always use new to create objects, so initialize might not be called. [link]

为了解决您的问题,您应该在回调中设置您的属性

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 功能的实例,因此您应该将参数传递给 newcreate 方法来测试它,但是您传递了 ImportFeed 到它(来自 FactoryGirl)。

根据文档,ActiveRecord#new 仅接受 Hash(如果您不传递任何内容,则默认参数为 {})。

如果您将对象传递给它,您将获得 ArgumentError 异常以及 "When assigning attributes, you must pass a hash as an argument" 消息

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