2012-04-16 9 views
26

मैंने पढ़ा है कि RSpec manual अंतर के बारे में क्या कहता है, लेकिन कुछ चीजें अभी भी भ्रमित हैं। "आरएसपीसी बुक" समेत हर दूसरे स्रोत में केवल "चलो" के बारे में बताया गया है, और "द रेल्स 3 वे" मैनुअल के रूप में भ्रमित है।रेल - आरएसपीसी - "चलो" और "चलो!" के बीच अंतर

मैं समझता हूं कि "चलो" का मूल्यांकन केवल तब किया जाता है जब आवंटित किया जाता है, और उसी मूल्य को एक दायरे में रखता है। तो यह समझ में आता है कि manual में पहले उदाहरण में पहला टेस्ट पास होता है क्योंकि "चलो" केवल एक बार लागू होता है, और दूसरा परीक्षण गुजरता है क्योंकि यह पहले टेस्ट के मान में जोड़ता है (जिसे पहले परीक्षण में एक बार मूल्यांकन किया गया था और 1 का मूल्य है)।

उसके बाद, "चलो!" परिभाषित किए जाने पर मूल्यांकन किया जाता है, और फिर जब बोला जाता है, तो परीक्षण को विफल नहीं होना चाहिए क्योंकि "count.should eq (1)" होना चाहिए "count.should eq (2)"?

किसी भी मदद की सराहना की जाएगी।

उत्तर

8

परिभाषित होने पर इसे लागू नहीं किया जाता है, बल्कि प्रत्येक उदाहरण से पहले (और फिर इसे याद किया जाता है और उदाहरण के द्वारा फिर से नहीं बुलाया जाता है)। इस तरह, गिनती वैसे 1.

के एक मूल्य होगा, अगर आप एक और उदाहरण है, हुक से पहले फिर से शुरू हो जाती है - निम्नलिखित परीक्षण के सभी पारित:

$count = 0 
describe "let!" do 
    invocation_order = [] 

    let!(:count) do 
    invocation_order << :let! 
    $count += 1 
    end 

    it "calls the helper method in a before hook" do 
    invocation_order << :example 
    invocation_order.should == [:let!, :example] 
    count.should eq(1) 
    end 

    it "calls the helper method again" do 
    count.should eq(2) 
    end 
end 
+0

सहमत हुए, यही कारण है कि पहला नमूना समझ में आता है। निश्चित रूप से, हालांकि, दूसरे spec का उदाहरण उदाहरण से पहले मूल्यांकन किया जाएगा, (इसे 1 के बराबर बनाते हैं) और फिर फिर "count.should" को कॉल करते समय (इसे 2 के बराबर बनाते हुए)? –

+3

नहीं, यह पहले से ही बुलाया गया है और याद किया गया है, इसलिए $ गिनती फिर से नहीं बढ़ी है। वैसे भी, यदि आपके पास एक और उदाहरण है, तो पहले हुक को फिर से बुलाया जाता है। मेरा संपादित उत्तर देखें, मैंने स्पष्टीकरण के लिए कुछ कोड जोड़ा। – dhoelzgen

+0

तो इसका मतलब यह होगा कि यदि आप "चलो" और एक स्पेक (एक "इसे") का उपयोग करते हैं तो "गिनती" नहीं करते हैं।"(या समान) होना चाहिए तो वृद्धि नहीं होगी? यदि ऐसा है, तो" चलो "को" पहले "नहीं माना जाना चाहिए, क्योंकि डिफ़ॉल्ट रूप से पहले" चलो! "की कार्यक्षमता का तात्पर्य है। क्या मुझे कुछ याद आ रहा है? –

21

आप इस here के बारे में और अधिक पढ़ सकते हैं, लेकिन मूल रूप से। (:let) आलसी मूल्यांकन किया गया है और यदि आप इसे कॉल नहीं करते हैं तो कभी भी तत्काल नहीं किया जाएगा, जबकि (:let!) प्रत्येक विधि कॉल से पहले बलपूर्वक मूल्यांकन किया जाता है।

+0

धन्यवाद जस्टिन। वह "मैनुअल" था जिसे मैंने उससे जोड़ा था, मुझे समझ में नहीं आया था। मेरा प्रश्न इस बात पर केंद्रित था कि उस लिंक में "दूसरा स्पेक" क्यों "गिनती है।" Eq (2) "के बजाय" count.should eq (2) "के साथ पारित किया गया। यदि विधि विधि से पहले इसका मूल्यांकन किया जाता है, और फिर जब "count.should" कहा जाता है, तो दूसरा उदाहरण 1 के बजाय 2 बराबर नहीं होना चाहिए? –

+1

हेल-फ्लिपिन-लुजा, आखिर में एक स्पष्टीकरण जो याद रखने या whetever के बारे में नहीं है। सरल और बिंदु, जैसा कि सबकुछ होना चाहिए। –

2

मैं भी let से उलझन में था और let!, तो मैं here से प्रलेखन कोड लिया और इसके साथ खेला: https://gist.github.com/3489451

आशा है कि यह मदद करता है!

+0

तय @JonathanLinErnSheong। यह कुछ चीजों को –

+0

को साफ़ करने के लिए अच्छा है! :) –

4

मैंने यह भी सोचा कि यह भ्रमित था, लेकिन मुझे लगता है कि रेल 3 वे के उदाहरण अच्छे हैं।
चलो पहले ब्लॉक में आवृत्ति चर के समान है जबकि चलो! तुरंत memoized है

रेल से 3 रास्ता

describe BlogPost do 
    let(:blog_post) { BlogPost.create :title => 'Hello' } 
    let!(:comment) { blog_post.comments.create :text => 'first post' } 

    describe "#comment" do 
    before do 
    blog_post.comment("finally got a first post") 
    end 

    it "adds the comment" do 
     blog_post.comments.count.should == 2 
    end 
    end 
end 

"जब से टिप्पणी ब्लॉक कभी नहीं पहले अभिकथन के लिए मार डाला गया होता अगर आप एक लेट परिभाषा का इस्तेमाल किया है, केवल एक टिप्पणी हो गया होता इस spec में जोड़ा गया है भले ही कार्यान्वयन काम कर रहा हो। चलो उपयोग करके! हम सुनिश्चित करते हैं कि प्रारंभिक टिप्पणी बनाई गई है और spec अब पास हो जाएगा। "

35

मुझे let और let! के बीच अंतर बहुत सरल उदाहरण के साथ अंतर समझा गया। मुझे पहले दस्तावेज़ वाक्य पढ़ने दो, फिर आउटपुट हाथ दिखाएं।

About let दस्तावेज़ कहते हैं: -

... let है आलसी से मूल्यांकन: यह पहली बार विधि में परिभाषित करता है शुरू हो जाती है जब तक मूल्यांकन नहीं किया गया है।

मैं नीचे दिए गए उदाहरण के साथ अंतर समझ में आ: -

$count = 0 
describe "let" do 
    let(:count) { $count += 1 } 

    it "returns 1" do 
    expect($count).to eq(1) 
    end 
end 

अब चला सकते हैं: -

[email protected]:~/Ruby> rspec spec/test_spec.rb 
F 

Failures: 

    1) let is not cached across examples 
    Failure/Error: expect($count).to eq(1) 

     expected: 1 
      got: 0 

     (compared using ==) 
    # ./spec/test_spec.rb:8:in `block (2 levels) in <top (required)>' 

Finished in 0.00138 seconds (files took 0.13618 seconds to load) 
1 example, 1 failure 

Failed examples: 

rspec ./spec/test_spec.rb:7 # let is not cached across examples 
[email protected]:~/Ruby> 

क्यों त्रुटि? क्योंकि, जैसा कि डॉक्टर ने कहा था, let, के साथ इसका मूल्यांकन तब तक नहीं किया जाता जब तक कि पहली बार जिस तरीके से परिभाषित किया जाता है, उसे लागू नहीं किया जाता है।उदाहरण में, हमने count का आह्वान नहीं किया, इस प्रकार $count अभी भी 0 है, 1 द्वारा वृद्धि नहीं हुई है।

अब let! भाग में आ रहा है। डॉक्टर

.... आप का उपयोग कर सकते हैं! प्रत्येक उदाहरण से पहले विधि के आवेषण को मजबूर करने के लिए। इसका मतलब यह भी है कि आपने सहायक विधि उदाहरण के अंदर विधि का आह्वान नहीं किया है, फिर भी यह आपके उदाहरण चलाने से पहले लागू किया जाएगा।

चलें यह भी परीक्षण: -:

[email protected]:~/Ruby> rspec spec/test_spec.rb 
. 

Finished in 0.00145 seconds (files took 0.13458 seconds to load) 
1 example, 0 failures 

देखें, अब $count रिटर्न 1, इस प्रकार परीक्षण -

यहाँ संशोधित कोड

$count = 0 
describe "let" do 
    let!(:count) { $count += 1 } 

    it "returns 1" do 
    expect($count).to eq(1) 
    end 
end 

इस कोड को चलाने देता है पारित हो गया ऐसा इसलिए हुआ क्योंकि मैंने let! का उपयोग किया, जो कि उदाहरण चलाने से पहले चलता है, हालांकि हमने हमारे उदाहरण के अंदर count नहीं बुलाया था।

इस प्रकार let और let! एक दूसरे से अलग है।

+2

सरल और स्पष्ट। धन्यवाद! –

+2

बहुत बहुत धन्यवाद! मैं इसे दो घंटों के लिए गुगल रहा हूं और अंत में मैं नीचे खड़ा! –

+0

ध्यान रखें, कभी भी ब्लॉक से पहले एक ब्लॉक ब्लॉक न करें, यह वही है! के लिए बनाया गया है अधिक जानकारी के लिए इस पृष्ठ को देखें: https://kolosek.com/rspec-let-vs- पहले –

1

और यहां आपके चश्मा अनुमान लगाने योग्य रखने का एक तरीका है।

आपको हमेशा let का उपयोग करना चाहिए। आपको let! का उपयोग नहीं करना चाहिए जबतक कि आप जानबूझकर उदाहरणों में मूल्य को कैश करना नहीं चाहते हैं। यही कारण है कि:

describe '#method' do 
    # this user persists in the db across all sub contexts 
    let!(:user) { create :user } 

    context 'scenario 1' do 
    context 'sub scenario' do 
     # ... 
     # 1000 lines long 
     # ... 
    end 

    context 'sub scenario' do 
     # you need to test user with a certain trait 
     # and you forgot someone else (or yourself) already has a user created 
     # with `let!` all the way on the top 
     let(:user) { create :user, :trait } 

     it 'fails even though you think it should pass' do 
     # this might not be the best example but I found this pattern 
     # pretty common in different code bases 
     # And your spec failed, and you scratch your head until you realize 
     # there are more users in the db than you like 
     # and you are just testing against a wrong user 
     expect(User.first.trait).to eq xxx 
     end 
    end 
    end 
end 
संबंधित मुद्दे