AssociationTypeMismatch和FactoryGirl

时间:2011-02-28 17:13:05

标签: ruby-on-rails ruby-on-rails-3 cucumber factory-bot

这最近引起了一些挫折......

似乎在我的黄瓜测试中使用工厂,在某些情况下会导致AssociationTypeMismatch错误,例如:

MyModel(#65776650)预期,得到MyModel(#28190030)(ActiveRecord :: AssociationTypeMismatch)

当存在关联引用时,似乎会发生这种情况 - 就好像Factory创建的对象与实际对象不同。有关详细信息,请参阅此问题:Cucumber duplicate class problem: AssociationTypeMismatch

我一直在逐步将Factory调用更改为真正的Model.create或mock_model调用。继续使用工厂女孩会很好......我想知道是否有什么我可能做错了?

谢谢

7 个答案:

答案 0 :(得分:8)

我在Rails 3.1.0 rc5上发生了这件事,并让它发挥作用。

扩展乔纳斯的答案。

您应该将Gemfile更改为:

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

然后如果你使用Spork,请使你的spec / spec_helper.rb文件看起来像这样:

Spork.each_run do
 require 'factory_girl'
 require 'factory_girl_rails'
end

答案 1 :(得分:4)

如果ActiveSupport卸载并重新加载您引用的常量,似乎会发生这种情况。 我和Rspec / Capybara有过相同的经历,并且有很多不同之处:

  • 确保在测试环境中将cached_classes设置为false(config / environments / test.rb)
  • 在您的gemspec中,尝试将'factory_girl_rails'替换为'factory_girl'

我正在使用Spork(测试服务器),这似乎使这些东西越来越难。 如果您使用的是测试服务器,请评估是否应该放置',:require =>错误'在你的gemspec中的factory_girl之后。

this google groups thread

中也涵盖了该主题

如果有任何帮助,请告诉我们。

答案 2 :(得分:4)

如果您正在使用Spork,请务必在重新加载模型后重新加载工厂

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

答案 3 :(得分:2)

这是因为cache_classes是假的,正如Spork所要求的那样。 Capybara为每个请求重新加载Rails类(或者,正确的是,Rails的重新加载器中间件没有,正常测试没有调用),这使工厂变得怪异(确切地说,为什么,我不确定)。你可以重新加载它们,或者只是在Spork之外运行你的Capybara规范。

所以你需要两件事:只在Spork之外运行Capybara,并且只为Spork设置cache_classes为false。

为了只在Spork之外运行Capybara,我有一个Guardfile,它在Spork之外的规范/请求中运行规范以及Spork内部的其他规范:

https://gist.github.com/1731900

然后,在config/environments/test.rb

config.cache_classes = !ENV['DRB']

你的水豚规格会慢一点,因为他们需要启动导轨,但一切都会正常工作。

答案 4 :(得分:1)

我在重新加载工厂定义方面取得了一些成功,试试这样:

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

答案 5 :(得分:1)

当我将“class”选项传递给其他工厂继承的工厂时,我遇到了这个问题:

factory :draft_resource, :class => Resource do

factory :resource, :parent => :draft_resource do

我能找到的唯一解决办法就是不要这样做。

答案 6 :(得分:0)

我遇到了同样的问题,大概花了十个小时尝试这个线程和网络上其他地方的每个解决方案。我开始掏出大量的代码试图让它接近我的另一个应用程序,我无法重现这个问题。最后,我在spec_helper文件中遇到了一些辅助函数:

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

sign_in帮助程序旨在兼容控制器和请求规范。确实如此 - 只是没有spork。当我删除水豚助手时问题得到了解决:

def sign_in(user)              
  cookies[:remember_token] = user.remember_token
end