AssociationTypeMismatch and FactoryGirl
Asked Answered
S

7

19

This has been causing some frustration recently...

It seems that using Factories in my cucumber tests, in some situations causes AssociationTypeMismatch errors such as:

MyModel(#65776650) expected, got MyModel(#28190030) (ActiveRecord::AssociationTypeMismatch)

These seem to happen when there is an association reference - as if the Factory created object is different to the real one. See this question for more details: Cucumber duplicate class problem: AssociationTypeMismatch

I have been gradually changing Factory calls to real Model.create or mock_model calls. It would be nice to keep using Factory girl... I wonder if there is something I may have done wrong?

Thank you

Scullery answered 28/2, 2011 at 17:13 Comment(3)
Note that this can also occur if you use reload! in a console window and then go on to create Factories. Solution is just to restart your console session.Certifiable
The solution about not having to use reload! mentioned by @Chrisbloom7 works. Just a bit of a pain to keep restarting rails consoleMisadvise
I ran into this exception when the class_name attribute was incorrectly set in the model.Camera
E
8

I had this happening with me on Rails 3.1.0 rc5, and got it working.

To expand on Jonas' answer.

You should change your Gemfile to be like this:

gem 'factory_girl', '~> 2.0.0', :require => false
gem 'factory_girl_rails', '~> 1.1.0', :require => false

And then if you are using Spork, make your spec/spec_helper.rb file look like this:

Spork.each_run do
 require 'factory_girl'
 require 'factory_girl_rails'
end
Evannia answered 14/8, 2011 at 21:24 Comment(2)
I also had to put this in my Spork.each_run (before the requires) to make it work: ActiveSupport::Dependencies.clear #Reload modelsCapillaceous
Thanks a lot. factory_girl is required by factory_girl_rails explicitly. So gem 'factory_girl_rails' and require 'factory_girl_rails' should be enough.Horny
S
4

It seems to happen if ActiveSupport unloads and reloads a constant that you have a reference to. I've experienced the same with Rspec/Capybara, and what helped was a mixture of different things:

  • Make sure you have cached_classes set to false in your test environment (config/environments/test.rb)
  • In your gemspec, try replacing require 'factory_girl_rails' with 'factory_girl'

I'm using Spork (a test server), which seems to make this stuff increasingly difficult. If you are using a test server, evaluate whether you should put ', :require => false' after factory_girl in your gemspec.

The topic is also covered in this google groups thread

Please let us know if any of this helped.

Solutrean answered 30/4, 2011 at 11:18 Comment(0)
C
4

If you're using Spork, make sure to reload your factories after reloading your models.

E.g.

Spork.each_run
  if Spork.using_spork?
    print "Reloading models ... "
    ActiveSupport::Dependencies.clear
    puts "done"

    print "Reloading factories ... "
    FactoryGirl.reload
    puts "done"
  end
end
Coastguardsman answered 21/1, 2013 at 21:41 Comment(0)
L
2

This happens because cache_classes is false, as is required by Spork. Capybara reloads Rails classes for every request (or, to be correct, Rails' reloader middleware does, which is not called for normal tests), and this freaks out the factories (exactly why, I'm not sure). You can either reload them, or simply run your Capybara specs outside of Spork.

So you need two things: to only run Capybara outside of Spork, and to set cache_classes to false only for Spork.

To only run Capybara outside of Spork, I have a Guardfile that runs specs in spec/requests outside of Spork and other specs inside of Spork here:

https://gist.github.com/1731900

Then, in config/environments/test.rb:

config.cache_classes = !ENV['DRB']

Your Capybara specs will be a bit slower, as they need to boot rails, but everything will Just Work.

Lynellelynett answered 3/2, 2012 at 19:32 Comment(0)
A
1

I had some success with reloading the Factory definitions try something like this:

class Factory
  def self.reload_definitions #:nodoc:
    self.factories.clear
    definition_file_paths.each do |path|
      load("#{path}.rb") if File.exists?("#{path}.rb")

      if File.directory? path
        Dir[File.join(path, '*.rb')].each do |file|
          load file
        end
      end
    end
  end
end
Astounding answered 8/6, 2011 at 15:36 Comment(0)
I
1

I ran into this issue when I passed the "class" option to my factory that was inherited by other factories:

factory :draft_resource, :class => Resource do

factory :resource, :parent => :draft_resource do

The only solution I could find was to simply not do this.

Imprecise answered 30/4, 2013 at 16:48 Comment(0)
V
0

I ran into this same issue and spent probably ten hours trying every solution on this thread and everywhere else on the web. I started ripping out huge chunks of code trying to get it as close to another app of mine in which I couldn't reproduce the problem. Finally, I came across some helper functions in my spec_helper file:

def sign_in(user)              
  visit signin_path            
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password 
  click_button "Sign in"       

  # Sign in when not using Capybara as well.
  cookies[:remember_token] = user.remember_token if defined?(cookies)
end

A sign_in helper intended to work both in controller and request specs. And it does, sort of--just not with spork. When I removed the capybara helpers the issue was resolved:

def sign_in(user)              
  cookies[:remember_token] = user.remember_token
end
Vitavitaceous answered 3/4, 2013 at 21:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.