Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

अस्थिर टेस्ट सूट को खत्म करना: विश्वसनीय API टेस्टिंग के लिए एक व्यावहारिक मार्गदर्शिका

मैं हाल ही में एक टेस्ट सूट पर काम कर रहा था जो अपनी अविश्वसनीयता के कारण उपयोग करने में वास्तव में निराशाजनक था।

वह एप्लिकेशन जिसे टेस्ट सूट लक्षित कर रहा था, एक रेल्स API-ओनली एप्लिकेशन था। टेस्ट JavaScript में Chakram नामक एक फ्रेमवर्क का उपयोग करके लिखे गए थे, "एक API टेस्टिंग फ्रेमवर्क जिसे JSON REST एंडपॉइंट्स पर एंड-टू-एंड टेस्ट करने के लिए डिज़ाइन किया गया है"।

टेस्ट सूट के साथ समस्या यह थी कि यह डिटरमिनिस्टिक नहीं था। एक फंक्शन या प्रोग्राम डिटरमिनिस्टिक होता है यदि, दिए गए समान इनपुट्स के लिए, यह हमेशा समान आउटपुट देता है।

यह विशेष टेस्ट सूट पहले रन पर पास होता, दूसरे रन पर पास होता, फिर तीसरे रन पर फेल होता - बिना एप्लिकेशन कोड या टेस्ट कोड में कोई बदलाव किए।

मैंने पाया कि मैं rake db:reset करके टेस्ट सूट को वापस पासिंग स्थिति में ला सकता हूं। टेस्ट, जो रेल्स एप्लिकेशन के डेवलपमेंट एनवायरनमेंट पर काम करते थे न कि टेस्ट एनवायरनमेंट पर, रेल्स एप्लिकेशन के डेटाबेस के एक निश्चित स्थिति में होने पर निर्भर थे जब टेस्ट सूट चलना शुरू होता था।

कभी-कभी मैं एक नए सीडेड डेटाबेस से शुरू कर सकता था, टेस्ट सूट चला सकता था, और फिर दूसरी बार टेस्ट सूट को सफलतापूर्वक चला सकता था। मैं टेस्ट सूट को तीन या अधिक बार भी चला सकता था। लेकिन अक्सर, टेस्ट सूट किसी तरह डेटा को खराब कर देता और मुझे डेटा को वापस उस स्थिति में लाने के लिए फिर से rake db:reset करना पड़ता जिसे टेस्ट सूट सफलतापूर्वक उपयोग कर सके।

यह निश्चित रूप से वह नहीं है जैसा होना चाहिए। एक टेस्ट सूट को केवल एक कारण से फेल होना चाहिए: वह कोड जिसे वह टेस्ट कर रहा है, ठीक से काम करना बंद कर देता है।

इसके बजाय क्या किया जाना चाहिए था

तो अगर यह टेस्ट सूट समस्याग्रस्त तरीके से सेट किया गया था, तो इसे करने का सही तरीका क्या होता?

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

टेस्ट सूट को रेल्स एप्लिकेशन के टेस्ट एनवायरनमेंट को टारगेट करना चाहिए था न कि डेवलपमेंट एनवायरनमेंट को। एक डेवलपर के डेवलपमेंट एनवायरनमेंट में कार्यों को टेस्ट सूट के काम में हस्तक्षेप नहीं करना चाहिए और इसके विपरीत।

अन्य प्रकार की समस्याग्रस्त निर्भरताएं

मेरी कहानी में, समस्याग्रस्त निर्भरता एक डेटाबेस थी जिसे ठीक से साफ नहीं किया जा रहा था।

एक अन्य प्रकार की समस्याग्रस्त निर्भरता नेटवर्क अनुरोध है। कल्पना करें कि आपके पास एक टेस्ट सूट है जो Twilio API को हिट करता है। आप मंगलवार को टेस्ट सूट चलाते हैं और यह पास होता है। फिर बुधवार को आप वही टेस्ट सूट चलाते हैं और यह फेल होता है। आपकी जानकारी के बिना, Twilio में आउटेज हो रहा है, और इसीलिए आपकी टेस्ट सूट फेल हुई। कुछ मिनट बाद आउटेज हल हो जाता है और आपकी टेस्ट सूट फिर से पास हो जाती है।

यह इस विचार पर वापस जाता है कि एक टेस्ट को केवल एक कारण से फेल होना चाहिए, और वह है यदि आपका एप्लिकेशन कोड काम करना बंद कर देता है।

यदि आपको नेटवर्क के साथ इंटरैक्ट करने वाले कोड के लिए टेस्ट लिखने की आवश्यकता है, तो ऐसा करने का एक बेहतर तरीका (यदि आप Ruby/Rails का उपयोग कर रहे हैं) VCR जैसे टूल का उपयोग करना है जो आपको नेटवर्क अनुरोधों को रिकॉर्ड करने और फिर वास्तव में इंटरनेट का उपयोग किए बिना बाद में उन्हें रीप्ले करने देता है।

वे मामले जब बाहरी निर्भरताएं ठीक हैं

यह तर्क दिया जा सकता है कि यदि कोई एप्लिकेशन Twilio API पर निर्भर करता है और Twilio API डाउन हो गया, तो एप्लिकेशन वास्तव में टूट गया और इसलिए टेस्ट को वास्तव में फेल होना चाहिए। हम इस विचार को इस विचार के साथ कैसे मेल खाते हैं कि टेस्ट्स को बाहरी स्थितियों पर निर्भर नहीं होना चाहिए?

इन दो चीजों को मेल खाने का तरीका इंटीग्रेशन टेस्ट्स के बीच अंतर करना है, जो एक साथ कई लेयर्स या सिस्टम्स को टेस्ट करते हैं, और यूनिट टेस्ट्स, जो एक ही कार्यक्षमता के टुकड़े को आइसोलेशन में टेस्ट करते हैं।

यदि कोई टीम यह सचेत निर्णय लेती है कि उनके टेस्ट्स का एक निश्चित सेट बाहरी सेवाओं को नेटवर्क पर हिट करने जा रहा है ताकि कई सिस्टम्स को एक साथ टेस्ट किया जा सके, तो इसमें कुछ भी "गलत" नहीं है। (विकल्प यह तय करना होगा कि उन सिस्टम्स को एक साथ टेस्ट करने का प्रयास ही न किया जाए।) इस परिदृश्य में टीम को बस इस बात की जानकारी होनी चाहिए कि उनका नेटवर्क-निर्भर इंटीग्रेशन टेस्ट सूट डिटरमिनिस्टिक होने की गारंटी नहीं है और शायद कभी-कभी फ्लेक आउट करेगा। इस तरह का एक टेस्ट सूट डेवलपर्स द्वारा हर दिन अपनी मशीनों पर रिग्रेशन की जांच के लिए चलाए जाने वाले टेस्ट्स के सेट से अलग रहना चाहिए।

जबकि इस नियम का अपवाद है कि टेस्ट्स को बाहरी स्थितियों पर निर्भर नहीं करना चाहिए, ज्यादातर समय नियम का पालन किया जाना चाहिए, जिससे आपके टेस्ट सूट को डिटरमिनिस्टिक और विश्वसनीय होने का लाभ मिले।

  1. प्रोडक्शन में RubyGems.org पर भरोसा करने की तुलना में स्वयं-होस्टेड Ruby Gems सुरक्षित क्यों हैं प्रोडक्शन में RubyGems.org पर भरोसा करने की तुलना में स्वयं-होस्टेड Ruby Gems सुरक्षित क्यों हैं

    एक भाषण + एक स्क्रीनकास्ट जो आपको दिखाता है कि अपने खुद के जेम्स कैसे होस्ट करें इसे रास्ते से हटा दें: जेम्स कमाल के हैं, और RubyGems.org एक बेहतरीन सेवा है। ...लेकिन हाल ही में मैं हर बार एक नया जेम ऐप में जोड़ने पर असहज महसूस कर रहा हूं। जितना अधिक मैं इसके बारे में सोचता हूं, उतना ही ऐसा लगता

  1. रूबी में VCR में महारत हासिल करें: टेस्ट परफॉरमेंस और विश्वसनीयता बढ़ाएं रूबी में VCR में महारत हासिल करें: टेस्ट परफॉरमेंस और विश्वसनीयता बढ़ाएं

    यदि आपका रूबी एप्लिकेशन किसी भी प्रकार के एक्सटर्नल API का उपयोग करता है तो आपने शायद धीमे टेस्ट्स और API रेट लिमिट्स की समस्या का सामना किया होगा। समाधान क्या है? आप अपने क्लाइंट लाइब्रेरी से HTTP मेथड्स को मैन्युअली स्टब कर सकते हैं, और कुछ पूर्व-निर्धारित प्रतिक्रियाएं वापस कर सकते हैं। लेकिन यह

  1. रूबी केस स्टेटमेंट्स में महारत: बहुमुखी उपयोग और व्यावहारिक उदाहरण रूबी केस स्टेटमेंट्स में महारत: बहुमुखी उपयोग और व्यावहारिक उदाहरण

    जब भी आपको कुछ if / elsif स्टेटमेंट्स का उपयोग करने की आवश्यकता होती है तो आप इसके बजाय रूबी केस स्टेटमेंट का उपयोग करने पर विचार कर सकते हैं। इस पोस्ट में, आप कुछ अलग उपयोग के मामले सीखेंगे और यह वास्तव में हुड के नीचे कैसे काम करता है। नोट: अन्य प्रोग्रामिंग भाषाओं में इसे स्विच स्टेटमेंट के रूप