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

时间:2018-04-25 08:33:34

标签: ruby-on-rails rspec factory-bot rspec-rails ruby-on-rails-5.1

这是我第一次在使用RSpec和FactoryGirl的rails项目上编写测试用例

当我运行测试用例时,我收到以下错误

  

错误的参数数量(给定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 :(得分:2)

因为你覆盖了initialize方法,所以你得到了意想不到的异常。

  

不要覆盖ActiveRecord对象的初始化   ActiveRecord :: Base并不总是使用new来创建对象,因此可能不会调用initialize。 [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功能的实例,因此您应该将params传递给newcreate方法来测试它,但是您传递的是{{1 (来自ImportFeed)。

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

如果您将对象传递给它,您将获得{}异常以及“在分配属性时,您必须将散列作为参数传递”消息

ArgumentError

答案 1 :(得分:1)

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

Overriding ApplicationRecord initialize, bad idea?