2012-12-30 253 views
4

UPDATE

我回去使用Fixtures。 IMOP,固定裝置的FAR優於工廠;更易於使用,更易於書寫,更易於理解(無魔術)。我的建議是:限制你的測試庫到非常基礎的地步(聽取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 "[email protected]" 
    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以繼續測試?

模型

school.rb

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

user.rb

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

district.rb

has_many :schools 

account.rb

belongs_to :role 
    belongs_to :user 

role.rb

has_many :accounts 
    has_many :users, :through => :accounts 
+0

你寫了一個學校的'has_many'用戶,但在你的工廠看來它只有一個用戶,就像'primarycontact'。你可以發佈這些模型的代碼(只是關聯信息的第一行)? –

+1

p.s.看看你的工廠代碼,看起來很清楚,問題在於你的學校工廠和你的用戶工廠之間存在循環依賴關係:一個學校有一個'primarycontact',它是使用'用戶'工廠,但'用戶'也有一所學校,這是使用'學校'工廠定義的。 –

+0

School belongs_to:primarycontact,:class_name =>「User」和has_many:users。不知道爲什麼我這樣做(舊代碼)...我想我會改變它來定義在用戶模型中使用布爾值的主要聯繫人。我在上面添加我現有的模型代碼...謝謝 – hellion

回答

11

您的基本問題是,你有你的user工廠和你school工廠,造成您創建一個primarycontact(用戶)的事實之間的循環依賴,當你創建一所學校,然後該用戶創建一所學校,等等。

您可以通過更改在user工廠內如何定義school關聯來解決此問題。在做這件事之前,我會建議使用關聯關係的速記符號作爲一般規則。所以替換此:

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 "[email protected]" 
    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中的回調語法已更改,有關詳細信息,請參閱documentation

+0

這是否意味着我需要重新定義一切:primarycontact,我定義在:user? (電子郵件地址爲「[email protected]ple.com」等) – Volte

+0

我最近放棄了工廠,回到了裝置。我喜歡它!我永遠不會再次使用工廠。 – hellion