2013-12-18 5 views
8

बनाम निर्माण मैं मॉडल User और Post, एक यूजर has_many पोस्ट और एक पोस्ट belongs_to एक उपयोगकर्ता है कहो।FactoryGirl साथ मॉडल चश्मा में संघों बढ़ाता है - बनाने बनाम build_stubbed

जब मैं Post के लिए एक कल्पना लिखते हैं, मेरी पहली वृत्ति कुछ इस तरह लिखने के लिए:

before do 
    @user = FactoryGirl.create :user 
    @post = @user.posts.new(title: "Foo", content: "bar) 
end 

... tests for @post go here ... 

लेकिन यह एक नया उपयोगकर्ता बनाने के लिए जा रहा है - हर एक परीक्षण के लिए है, जो - डेटाबेस से टकराने चीजों को धीमा करने जा रहा है। क्या ऐसा करने का एक बेहतर तरीका है जो मेरे परीक्षणों को गति देगा और डीबी को इतनी बार मारने से बचें?

मैं यह समझ के रूप में, मैं FactoryGirl.build :user उपयोग कर सकते हैं नहीं है, क्योंकि भले ही यह डीबी मारा नहीं होगा, संघों ठीक से काम नहीं करेगा क्योंकि @user एक आईडी की जरूरत नहीं होगी और इतने @post.user काम नहीं करेगा (यह nil देता है।)

मैं FactoryGirl.build_stubbed :user जो एक बनाया इस्तेमाल कर सकते हैं "नकली कायम" @user जो एक आईडी होनी करता है, लेकिन अभी भी @post.user शून्य देता है। build_stubbed पर build पर कोई व्यावहारिक लाभ है जब मैं एसोसिएशन से संबंधित चीजों का परीक्षण कर रहा हूं?

मुझे लगता है कि मैं build_stubbed स्टब @post.user का उपयोग कर सकता हूं, इसलिए यह @user लौटाता है ... क्या कोई कारण यह बुरा विचार हो सकता है?

या मुझे बस create का उपयोग करना चाहिए और गति हिट स्वीकार करना चाहिए?

एकमात्र अन्य विकल्प जो मैं सोच सकता हूं, @user को before(:all) ब्लॉक में स्थापित करना होगा जो एक बुरा विचार जैसा लगता है।

इस तरह के परीक्षणों को एक स्वच्छ, संक्षिप्त तरीके से लिखने का सबसे अच्छा तरीका क्या है जो बहुत सारे डीबी प्रश्नों से बचाता है?

उत्तर

18

यदि आप नहीं चाहते हैं कि आपके परीक्षण डेटाबेस को मार रहे हों, तो आपको यही करना होगा।

before do 
    @user = FactoryGirl.build_stubbed :user 
    @post = FactoryGirl.build_stubbed :post 
    @user.stub(:posts).and_return([@post]) 
    @post.stub(:user).and_return(@user) 
end 

नोट: before(:all) का उपयोग करते समय सावधान रहें। यह एक लेनदेन में निष्पादित नहीं किया जाता है। तो जो भी आप before(:all) में बनाते हैं, डेटाबेस में पीछे छोड़ दिया जाएगा और अन्य परीक्षणों के साथ संघर्ष हो सकता है

लगभग FactoryGirl.build, यह ऑब्जेक्ट बनाता है, लेकिन एसोसिएशन बनाता है।

उदाहरण के लिए:

factory :user do 
    association posts 
end 

FactoryGirl.build(:user) #this creates posts in the database even though you are only building the parent object(user) 
15

लघु उत्तर

@user = FactoryGirl.build_stubbed(:user) 
@post = FactoryGirl.build_stubbed(:post, :user => @user) 

यह कभी डेटाबेस से टकराने के बिना @ post.user काम कर देगा।

लांग उत्तर

मेरे सिफारिश जब तक आप वाकई इसकी जरूरत हो before खंड पर इंतजार करना होगा। इसके बजाए, प्रत्येक व्यक्तिगत परीक्षण के लिए आवश्यक डेटा बनाएं और विधियों या नए कारखानों को डुप्लिकेट निकालें जैसा आपको लगता है।

इसके अलावा, क्या आपको वास्तव में प्रत्येक परीक्षण में उपयोगकर्ता को संदर्भित करने की आवश्यकता है? प्रत्येक परीक्षण में उपलब्ध @user होने से अन्य डेवलपर्स को यह कहते हैं कि यह हर जगह महत्वपूर्ण है।

आखिरकार, यह मानते हुए कि उपयोगकर्ता पोस्ट को आपके पोस्ट फैक्ट्री में भी घोषित किया गया है, तो आप post.user पर स्वचालित रूप से काम कर लेंगे जब आप build_stubbed(:post) करते हैं।

8

create, build, और build_stubbed के बीच अंतर को भूलना आसान हो सकता है। यहां एक ही स्थिति में उन लोगों के लिए एक त्वरित संदर्भ दिया गया है (क्योंकि यह पृष्ठ खोज परिणामों में अत्यधिक है)।

# Returns a User instance that's not saved (does not write to DB) 
user = build(:user) 

# Returns a saved User instance (writes to DB) 
user = create(:user) 

# Returns a hash of attributes that can be used to build a User instance 
attrs = attributes_for(:user) 

# Returns an object with all defined attributes stubbed out 
stub = build_stubbed(:user) 

# Passing a block to any of the methods above will yield the return object 
create(:user) do |user| 
    user.posts.create(attributes_for(:post)) 
end 

Source

1

कारखाने महिला के दस्तावेज़ से, आप रणनीति builduser के लिए संघ में post कारखाने में इस तरह की पहचान कर सकते हैं:

factory :post do 
    association :user, factory: :user, strategy: :build 
end 

ताकि तुम build कर सकते हैं एक post बिना बचाने के user

post = build(:post) 
post.new_record?  # => true 
post.author.new_record? # => true 
संबंधित मुद्दे