5

更新

我又开始使用 Fixtures。IMOP,夹具比工厂好得多;更容易使用,更容易编写,更容易理解(没有魔法)。我的建议:将您的测试库限制在最基本的范围内(听 DHH)...使用带有夹具的 minitest。

原帖

在我的应用程序中,一个地区有很多学校,一个学校有很多用途,一个用户有很多账户,一个账户有一个角色。为了创建完整的工厂进行测试,我需要创建一个跨工厂持续存在的用户和学校。在我最近的尝试中,我遇到了“堆栈级别太深”的错误。

我的 user_test.rb

 FactoryGirl.define do

   factory :district do
     name "Seattle"
   end

   factory :school do
     association :primarycontact, factory: :user # expecting this to attach the user_id from factory :user as :primary contact_id in the school model
     association :district, factory: :district # expecting this to attach the :district_id from the :district factory as :district_id in the school model
     name "Test School"
   end

   factory :user do, aliases: [:primarycontact]
     email "adam@example.com"
     name "Who What"
     username "wwhat"
     password "123456"
     password_confirmation { |u| u.password }
     association :school, factory: :school # expecting this to create :school_id in the users model, using the :school factory
   end

   factory :role do
     name "student"
   end

   factory :account do
     association :user, factory: :user
     association :role, factory: :role
   end

 end

因此,我正在尝试FactoryGirl.create(:account)...创建一个帐户,该帐户具有上述工厂的用户和角色,以及与该地区相关联的学校相关联的用户。这对我不起作用。在失败的测试中,我得到一个“堆栈级别太深”的错误。而且,我相信我在每个 DatabaseCleaner.clean 之前都会在每个新工厂之前清除测试数据库。

调用这些工厂的测试是:

describe "User integration" do

  def log_em_in
    visit login_path
    fill_in('Username', :with => "wwhat")
    fill_in('Password', :with => "123456")
    click_button('Log In')
  end

  it "tests log in" do
    user = FactoryGirl.create(:account)
    log_em_in
    current_path.should == new_user_path
  end

end

.

current_path.should == new_user_path returns unknown method error 'should'

如何改进此代码以正确嵌套工厂并获取 current_user 以继续测试?

楷模

学校.rb

  belongs_to :district
  belongs_to :primarycontact, :class_name => "User"
  has_many :users, :dependent => :destroy

用户.rb

  belongs_to :school
  has_many :accounts, :dependent => :destroy

区.rb

  has_many :schools

帐号.rb

  belongs_to :role
  belongs_to :user

角色.rb

  has_many :accounts
  has_many :users, :through => :accounts
4

1 回答 1

12

您的基本问题是您的user工厂和您的school工厂之间存在循环依赖关系,这是由于您primarycontact在创建学校时创建了一个(用户),然后该用户创建了学校,等等。

您可以通过更改在工厂school内定义关联的方式来解决此问题。user不过,在这样做之前,我建议作为一般规则使用关联的速记符号。所以替换这个:

factory :account do
  association :user, factory: :user
  association :role, factory: :role
end

有了这个:

factory :account do
  user
  role
end

使用这种简化,以下工厂将做你想做的事,而不会产生任何循环依赖:

FactoryGirl.define do

  factory :district do
    name "Seattle"
  end

  factory :school do |school|
    district
    primarycontact
    name "Test School"
    after_build do |s|
      s.primarycontact.school = s
    end
  end

  factory :user do
    email "adam@example.com"
    name "Who What"
    username "wwhat"
    password "123456"
    password_confirmation { |u| u.password }
    school
  end

  factory :primarycontact, class: "User" do
    # add any attributes you want the primarycontact user to have here
  end

  factory :role do
    name "student"
  end

  factory :account do
    user
    role
  end

end

请注意,我所做的是primarycontact使用该class: "User"选项创建工厂。与user工厂不同,该工厂默认不创建school,避免了循环依赖。

然后在school工厂中,我使用after_build回调将学校本身分配给 上的school关联primarycontact,而不是创建新学校(这导致您的工厂出现问题)。

希望这是有道理的。请注意,最新版本的 factory_girl 中的回调语法已更改,有关详细信息,请参阅文档

于 2013-01-01T08:14:46.300 回答