Search code examples
ruby-on-railsrspecfactory-botrspec-railsruby-on-rails-5.1

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


This is the first time I am writing test cases on a rails project which is using RSpec and FactoryGirl

When I run the test case i get the following error

wrong number of arguments (given 0, expected 1)

I have gone through other posts at stack over flow and they are not much helpful in my case.

What I have tried

I am writing a test case on a Model which is called ImportFeed and it looks something like as following

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

This is what my test case looks like

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

This is the factory

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

When I run this I get the error mentioned at the beginning of this question,

If I pass the data to the test case without FactoryGirl then my test case works and passes for example if I replace

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

with

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

the test case passes.

I will really appreciate if someone can point to me what am I doing wrong here.


Solution

  • Because you're overriding initialize method, so you got unexpected exception.

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

    In order to solve your problem, you should set your attributes in callback instead

    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
    

    One more thing:

    You're testing creating an instance of ImportFeed functionality, so you should either pass params to new or create methods to test it, but you pass an instance of ImportFeed to it (from FactoryGirl).

    According to the docs, ActiveRecord#new accepts Hash only (the default argument is {} if you don't pass anything).

    If you pass an object to it, you'll get ArgumentError exception along with "When assigning attributes, you must pass a hash as an argument" message

    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