RSpec के विषय और चलो में क्या अंतर है? इन्हें कब इस्तेमाल किया जाना चाहिए या नहीं?


86

http://betterspecs.org/#subject के बारे में कुछ जानकारी subjectऔर है let। हालाँकि, मैं अभी भी उनके बीच अंतर पर स्पष्ट नहीं हूँ। इसके अलावा, एसओ पोस्ट RSpec परीक्षणों में पहले, जाने और विषय का उपयोग करने के खिलाफ तर्क क्या है? यह बेहतर है कि subjectया तो उपयोग न करें या let। मैं कहाँ जाऊं? मैं बहुत उलझा हुआ हूं।

जवाबों:


191

सारांश: RSpec का विषय एक विशेष चर है जो कि परीक्षण की जा रही वस्तु को संदर्भित करता है। इस पर उम्मीदें निहित की जा सकती हैं, जो एक-पंक्ति के उदाहरणों का समर्थन करता है। यह कुछ मुहावरेदार मामलों में पाठक को स्पष्ट है, लेकिन अन्यथा समझने में कठिन है और इसे टाला जाना चाहिए। RSpec के letचर केवल आलसी तात्कालिक (याद किए गए) चर हैं। वे विषय के रूप में पालन करने के लिए कठिन नहीं हैं, लेकिन अभी भी पेचीदा परीक्षणों का नेतृत्व कर सकते हैं इसलिए विवेक के साथ उपयोग किया जाना चाहिए।

विषय

यह काम किस प्रकार करता है

विषय वस्तु का परीक्षण किया जा रहा है। RSpec में विषय का एक स्पष्ट विचार है। यह परिभाषित किया जा सकता है या नहीं। यदि यह है, तो RSpec स्पष्ट रूप से संदर्भित किए बिना इस पर तरीके कह सकता है।

डिफ़ॉल्ट रूप से, यदि बाहरी उदाहरण समूह ( describeया contextब्लॉक) के लिए पहला तर्क एक वर्ग है, तो RSpec उस वर्ग का एक उदाहरण बनाता है और उसे विषय पर असाइन करता है। उदाहरण के लिए, निम्नलिखित पास:

class A
end

describe A do
  it "is instantiated by RSpec" do
    expect(subject).to be_an(A)
  end
end

आप इस विषय को खुद से परिभाषित कर सकते हैं subject:

describe "anonymous subject" do
  subject { A.new }
  it "has been instantiated" do
    expect(subject).to be_an(A)
  end
end

जब आप इसे परिभाषित करते हैं तो आप विषय को एक नाम दे सकते हैं:

describe "named subject" do
  subject(:a) { A.new }
  it "has been instantiated" do
    expect(a).to be_an(A)
  end
end

यदि आप विषय का नाम रखते हैं, तो भी आप इसे गुमनाम रूप से संदर्भित कर सकते हैं:

describe "named subject" do
  subject(:a) { A.new }
  it "has been instantiated" do
    expect(subject).to be_an(A)
  end
end

आप एक से अधिक नामित विषय को परिभाषित कर सकते हैं। सबसे हाल ही में परिभाषित नाम विषय गुमनाम है subject

हालाँकि विषय परिभाषित है,

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

  2. इस पर अपेक्षाएं निहित की जा सकती हैं (बिना लिखे subjectया किसी नामित विषय के)

    describe A do
      it { is_expected.to be_an(A) }
    end
    

    विषय इस एक-पंक्ति सिंटैक्स का समर्थन करने के लिए मौजूद है।

इसका उपयोग कब करें

एक अंतर्निहित subject(उदाहरण समूह से अनुमानित) को समझना मुश्किल है क्योंकि

  • यह पर्दे के पीछे तात्कालिक है।
  • चाहे इसका उपयोग स्पष्ट रूप से ( is_expectedस्पष्ट रिसीवर के बिना कॉल करके ) या स्पष्ट रूप से किया गया हो (जैसा किsubject ) उपयोग किया जाता है, यह पाठक को उस वस्तु की भूमिका या प्रकृति के बारे में कोई जानकारी नहीं देता है जिस पर उम्मीद की जा रही है।
  • वन-लाइनर उदाहरण सिंटैक्स में उदाहरण विवरण ( itसामान्य उदाहरण सिंटैक्स में स्ट्रिंग तर्क ) नहीं होता है, इसलिए पाठक को केवल उदाहरण के उद्देश्य के बारे में जानकारी ही अपेक्षा होती है।

इसलिए, यह केवल एक अंतर्निहित विषय का उपयोग करने के लिए उपयोगी है जब संदर्भ को सभी पाठकों द्वारा अच्छी तरह से समझा जा सकता है और उदाहरण के विवरण की वास्तव में कोई आवश्यकता नहीं है । विहित मामला सक्रिय मिलान सत्यापनों के साथ कंधे मिलानकर्ताओं का परीक्षण कर रहा है:

describe Article do
  it { is_expected.to validate_presence_of(:title) }
end

एक खोज अनाम subject( subjectनाम के बिना परिभाषित ) थोड़ा बेहतर है, क्योंकि पाठक देख सकता है कि यह कैसे त्वरित है, लेकिन

  • यह अभी भी उस विषय की तात्कालिकता को दूर रख सकता है जहाँ से इसका उपयोग किया जाता है (उदाहरण के लिए एक उदाहरण समूह के शीर्ष पर कई उदाहरण जो इसका उपयोग करते हैं), जिसका पालन करना अभी भी कठिन है, और
  • यह अन्य समस्याएं हैं जो अंतर्निहित विषय करता है।

एक नामित विषय एक इरादा-प्रकट करने वाला नाम प्रदान करता है, लेकिन एक letचर के बजाय एक नामित विषय का उपयोग करने का एकमात्र कारण यह है कि यदि आप अनाम विषय का कुछ समय का उपयोग करना चाहते हैं, और हमने अभी बताया कि अनाम विषय को समझना कठिन क्यों है।

तो, एक स्पष्ट अनाम subjectया एक नामित विषय के वैध उपयोग बहुत दुर्लभ हैं

let चर

वे कैसे काम करते हैं

let चर केवल दो अंतरों को छोड़कर नामित विषयों की तरह हैं:

  • वे के साथ परिभाषित कर रहे हैं let/ let!के बजाय subject/subject!
  • वे अनाम सेट नहीं करते हैं subjectया अपेक्षाओं को इस पर कॉल करने की अनुमति नहीं देते हैं।

उनका उपयोग कब करना है

letउदाहरणों के बीच दोहराव को कम करने के लिए उपयोग करना पूरी तरह से वैध है । हालाँकि, ऐसा तभी करें जब यह टेस्ट क्लैरिटी का त्याग न करे। उपयोग करने का सबसे सुरक्षित समय letवह होता है जब letचर का उद्देश्य अपने नाम से पूरी तरह से स्पष्ट होता है (ताकि पाठक को परिभाषा नहीं मिलनी चाहिए, जो कई पंक्तियों को दूर कर सकता है, प्रत्येक उदाहरण को समझने के लिए) और यह उसी तरह से उपयोग किया जाता है हर उदाहरण में। यदि उन चीजों में से कोई भी सत्य नहीं है, तो एक सादे पुराने स्थानीय चर में वस्तु को परिभाषित करने या उदाहरण में फ़ैक्टरी विधि को सही कहने पर विचार करें।

let!जोखिम भरा है, क्योंकि यह आलसी नहीं है। यदि कोई उदाहरण समूह में एक उदाहरण जोड़ता है जिसमें प्रारूप है let!, लेकिन उदाहरण को let!चर की आवश्यकता नहीं है ,

  • उस उदाहरण को समझना कठिन होगा, क्योंकि पाठक let!चर को देखेगा और आश्चर्य करेगा कि क्या और कैसे इस उदाहरण को प्रभावित करता है
  • उदाहरण के लिए धीमी गति से हो जाएगा, क्योंकि यह समय बनाने के लिए लिया जाता है, क्योंकि let!चर बनाने के लिए

तो उपयोग करें let!, यदि बिल्कुल, केवल छोटे, सरल उदाहरण समूहों में, जहां यह संभावना कम है कि भविष्य के उदाहरण लेखक उस जाल में गिर जाएंगे।

एकल-अपेक्षा-प्रति-उदाहरण बुत

विषयों या letचर का एक सामान्य अति प्रयोग है जो अलग से चर्चा करने लायक है। कुछ लोग उन्हें इस तरह से उपयोग करना पसंद करते हैं:

describe 'Calculator' do
  describe '#calculate' do
    subject { Calculator.calculate }
    it { is_expected.to be >= 0 }
    it { is_expected.to be <= 9 }
  end
end

(यह एक विधि का एक सरल उदाहरण है जो एक संख्या देता है जिसके लिए हमें दो अपेक्षाओं की आवश्यकता होती है, लेकिन इस शैली के कई और उदाहरण / अपेक्षाएं हो सकती हैं यदि विधि अधिक जटिल मान लौटाती है जिसे कई अपेक्षाओं और / या कई दुष्प्रभावों की आवश्यकता होती है जो सभी को उम्मीदें हैं।)

लोग ऐसा इसलिए करते हैं क्योंकि उन्होंने सुना है कि प्रति उदाहरण के लिए केवल एक ही अपेक्षा होनी चाहिए (जो कि वैध नियम के साथ मिश्रित है कि किसी को प्रति उदाहरण केवल एक विधि कॉल का परीक्षण करना चाहिए) या क्योंकि वे RSpec चालबाजी के साथ प्यार में हैं। एक अनाम या नामित विषय या एक letचर के साथ, यह मत करो ! इस शैली में कई समस्याएं हैं:

  • अनाम विषय उदाहरणों का विषय नहीं है - विधि विषय है। परीक्षा को इस तरह से लिखने से भाषा खराब हो जाती है, जिसके बारे में सोचना मुश्किल हो जाता है।
  • हमेशा की तरह वन-लाइन उदाहरणों के साथ, उम्मीदों का अर्थ समझाने के लिए कोई जगह नहीं है।
  • प्रत्येक उदाहरण के लिए विषय का निर्माण किया जाना है, जो धीमा है।

इसके बजाय, एक एकल उदाहरण लिखें:

describe 'Calculator' do
  describe '#calculate' do
    it "returns a single-digit number" do
      result = Calculator.calculate
      expect(result).to be >= 0
      expect(result).to be <= 9
    end
  end
end

17
वाह! + 💯! "एकल-अपेक्षा-प्रति-उदाहरण बुत" सोने में अपने वजन के लायक है, इसलिए बोलने के लिए। मुझे कभी भी उस (गलत) नियम का बहुत बारीकी से पालन करने की आवश्यकता महसूस नहीं हुई है, लेकिन अब मैं उन लोगों के खिलाफ अच्छी तरह से सशस्त्र हूं जो इसे हममें से बाकी लोगों पर लागू करने की कोशिश करते हैं। धन्यवाद!
मूर्ति

2
इसके अलावा, यदि आप चाहते हैं कि आपकी बहु-प्रत्याशा ब्लॉक सभी उम्मीद की रेखाओं को चलाने के बजाय (यदि पहली असफलता नहीं चल रही है तो) आप :aggregate_failuresएक पंक्ति में टैग का उपयोग कर सकते हैं जैसे it ​"marks a task complete"​, ​:aggregate_failures​ ​do(पुस्तक रेल 5 टेस्ट पर्चे से लिया गया)
भूलभुलैया

1
मैं सभी पाखंडों के खिलाफ हूं और यह भी कहना चाहता हूं, "एकल-अपेक्षा-प्रति-उदाहरण" मुख्य रूप से उन लोगों के लिए है जो एक ही उदाहरण में कई असंबंधित उम्मीदों को समूह बनाना पसंद करते हैं। शब्दार्थ, आपका उदाहरण आदर्श नहीं है, क्योंकि यह एक अंक की संख्या के लिए मान्य नहीं है, यह वास्तविक संख्या के लिए मान्य है [0, 9] -, जो आश्चर्यचकित कर देता है, जो एक बहुत अधिक पठनीय एक एकल अपेक्षा में कोडित हो सकता है expect(result).to be_between(0, 9)
आंद्रे फिग्यूएरेडो

यदि आप केवल एकल अंक संख्या (Int [0,9]) के लिए मान्य करना चाहते हैं, तो यह करना अधिक उपयुक्त होगा expect(result.to_s).to match(/^[0-9]$/)- मुझे पता है कि यह बदसूरत है, लेकिन यह वास्तव में परीक्षण करता है कि आप क्या कह रहे हैं, या शायद, उपयोग करेंbetween + काis_a? Integer , लेकिन यहां आप परीक्षण कर रहे हैं प्रकार भी। और बस let.. यह चिंता का विषय नहीं होना चाहिए, और उदाहरणों के बीच मूल्यों का पुनर्मूल्यांकन करना वास्तव में बेहतर हो सकता है। अन्यथा पोस्ट के लिए +1
आंद्रे फिगयेरिडो

मैं के खतरों के बारे में आपके स्पष्टीकरण से प्यार करता हूं let! और अपने साथियों को अपने दम पर समझाने के लिए नहीं। मैं इस जवाब को भेजने जा रहा हूँ।
डेमन

5

Subjectऔर letआपके परीक्षण को तेज करने और आपकी मदद करने के लिए सिर्फ उपकरण हैं। Rspec समुदाय के लोग इनका उपयोग करते हैं इसलिए मुझे इस बात की चिंता नहीं होगी कि उनका उपयोग करना ठीक है या नहीं। उनका उपयोग समान रूप से किया जा सकता है लेकिन थोड़े अलग उद्देश्यों के लिए

Subjectआपको एक परीक्षण विषय घोषित करने की अनुमति देता है, और उसके बाद किसी भी निम्नलिखित परीक्षण मामलों के लिए इसका पुन: उपयोग करता है। यह कोड पुनरावृत्ति को कम करता है (अपने कोड को कम करना)

Letbefore: eachब्लॉक का एक विकल्प है , जो चर का उदाहरण देने के लिए परीक्षण डेटा प्रदान करता है। Letआपको कुछ फायदे देता है। सबसे पहले, यह एक उदाहरण चर को निर्दिष्ट किए बिना मूल्य को कैश करता है। दूसरा, यह आलसी रूप से मूल्यांकन किया गया है, जिसका अर्थ है कि इसका मूल्यांकन तब तक नहीं मिलता है जब तक कि इसके लिए एक कल्पना कॉल न हो। इस प्रकार letआपको अपने परीक्षणों को गति देने में मदद मिलती है। मुझे भी लगता letहै कि पढ़ना आसान है


1

subjectपरीक्षण के तहत, आमतौर पर एक उदाहरण या एक वर्ग है। letआपके परीक्षणों में वैरिएबल निर्दिष्ट करने के लिए है, जिनका उदाहरण आलसी बनाम उदाहरण चर का उपयोग करके किया जाता है। इस सूत्र में कुछ अच्छे उदाहरण हैं।

https://github.com/reachlocal/rspec-style-guide/issues/6

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.