"अच्छा" इकाई परीक्षण कैसे लिखें?


61

इस धागे से त्रस्त , मैं (फिर से) अपनी परियोजनाओं में इकाई परीक्षणों का उपयोग करने के बारे में सोच रहा हूं। कुछ पोस्टरों में कहा गया है कि "टेस्ट अच्छे हैं, अगर वे अच्छे टेस्ट हैं"। मेरा सवाल अब: "अच्छे" परीक्षण क्या हैं?

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


8
किसी भी अच्छी इकाई का परीक्षण केवल एक चीज का परीक्षण करना चाहिए - यदि यह विफल हो जाता है तो आपको पता होना चाहिए कि क्या गलत हुआ।
गैबलिन

2
बड़ी मात्रा में डेटा होने पर अच्छी बात यह है कि जेनेरिक परीक्षण लिखें जो डेटा फ़ाइलों को इनपुट के रूप में ले सकते हैं। डेटा फ़ाइलों में आमतौर पर इनपुट और अपेक्षित परिणाम दोनों शामिल होने चाहिए। Xunit परीक्षण ढांचे के साथ आप मक्खी पर परीक्षण के मामले उत्पन्न कर सकते हैं - प्रत्येक डेटा नमूने के लिए।
फ्रोडरिक

2
@ गैबलिन "यदि यह विफल हो जाता है तो आपको पता होना चाहिए कि क्या गलत हुआ" यह सुझाव देगा कि कई संभावित विफलता कारणों के साथ परीक्षण ठीक हैं, जब तक आप परीक्षण के आउटपुट से कारण निर्धारित कर सकते हैं ...?
user253751

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

जवाबों:


52

यूनिट परीक्षण के बारे में कहने के लिए आर्ट ऑफ़ यूनिट टेस्टिंग निम्नलिखित है:

एक इकाई परीक्षण में निम्नलिखित गुण होने चाहिए:

  • यह स्वचालित और दोहराने योग्य होना चाहिए।
  • इसे लागू करना आसान होना चाहिए।
  • एक बार यह लिखे जाने के बाद, यह भविष्य में उपयोग के लिए बना रहना चाहिए।
  • कोई भी इसे चलाने में सक्षम होना चाहिए।
  • यह एक बटन के धक्का पर चलना चाहिए।
  • इसे जल्दी से चलना चाहिए।

और फिर बाद में कहते हैं कि यह पूरी तरह से स्वचालित, विश्वसनीय, पठनीय और रखरखाव योग्य होना चाहिए।

यदि आप पहले से ही इस पुस्तक को पढ़ने की जोरदार सलाह देंगे।

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


1
यूनिट परीक्षण पर लक्षित एक व्यापक सूची के लिए +1 (एकीकरण या कार्यात्मक परीक्षण नहीं)
गैरी रोवे

1
लिंक के लिए +1। वहां मिलने वाली रोचक सामग्री।
जोरिस मेय्स

1
"जल्दी से भागो" बड़े निहितार्थ हैं। यह एक कारण है कि यूनिट परीक्षणों को अलग-अलग संसाधनों में चलना चाहिए, जैसे कि बाहरी संसाधनों से दूर रहना चाहिए, जैसे डेटाबेस, फाइल सिस्टम, वेब सेवा आदि। यह, बदले में, मोक्स / स्टब्स की ओर जाता है।
माइकल ईस्टर

1
जब यह कहता है It should run at the push of a button, तो इसका मतलब यह है कि एक इकाई परीक्षण के लिए कंटेनर (ऐप सर्वर) चलाने की आवश्यकता नहीं है (इकाई परीक्षण किया जा रहा है) या संसाधन कनेक्शन (जैसे डीबी, बाहरी वेब सेवाएं आदि)? मैं बस के रूप में उलझन में हूँ कि एक आवेदन के किन हिस्सों में इकाई परीक्षण किया जाना चाहिए और कौन सा नहीं होना चाहिए। मुझे बताया गया है कि यूनिट परीक्षणों के लिए डीबी कनेक्शन और रनिंग कंटेनरों पर निर्भर रहना चाहिए और शायद इसके बजाय मॉकअप का उपयोग करना चाहिए।
उभयलिंगी

42

एक अच्छी इकाई परीक्षण उस परीक्षण को प्रतिबिंबित नहीं करता है।

एक बहुत ही सरल उदाहरण के रूप में, विचार करें कि आपके पास एक ऐसा फ़ंक्शन है जो औसतन दो int का रिटर्न देता है। सबसे व्यापक परीक्षण फ़ंक्शन को कॉल करेगा और जांच करेगा कि क्या परिणाम वास्तव में एक औसत है। इसका कोई मतलब नहीं है: आप जिस कार्यक्षमता का परीक्षण कर रहे हैं उसे प्रतिबिंबित (प्रतिकृति) कर रहे हैं। यदि आपने मुख्य फ़ंक्शन में कोई गलती की है, तो आप परीक्षण में वही गलती करेंगे।

दूसरे शब्दों में, यदि आप इकाई परीक्षण में मुख्य कार्यक्षमता की नकल करते हुए पाते हैं, तो यह एक संभावित संकेत है कि आप अपना समय बर्बाद कर रहे हैं।


21
+1 इस मामले में आप क्या करेंगे, हार्डकॉक्ड तर्कों के साथ परीक्षण करें और अपने ज्ञात उत्तर के खिलाफ जांच करें।
माइकल के

मैंने उस गंध को पहले देखा है।
पॉल कसाई

क्या आप उस फ़ंक्शन के लिए एक अच्छी इकाई परीक्षा का उदाहरण दे सकते हैं जो औसत रिटर्न देता है?
वीएलएएस

2
@ वीएलएएस परीक्षण पूर्वनिर्धारित मूल्यों, उदाहरण के लिए सुनिश्चित करें कि एवीजी (1, 3) == 2, और भी महत्वपूर्ण रूप से किनारे के मामलों की जांच करें, जैसे कि INT_MAX, शून्य, नकारात्मक मान, आदि। यदि कोई बग पाया गया और फ़ंक्शन में तय किया गया है, तो एक और जोड़ें। यह सुनिश्चित करने के लिए परीक्षण करें कि यह बग कभी फिर से पेश न किया जाए।
मोजुबा

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

10

अच्छा इकाई परीक्षण अनिवार्य रूप से विशिष्ट रूप में विनिर्देशन है:

  1. मामलों का उपयोग करने के लिए इसी कोड के व्यवहार का वर्णन करें
  2. कवर तकनीकी कोने के मामले (क्या होता है यदि शून्य पास है) - यदि एक कोने के मामले के लिए एक परीक्षण मौजूद नहीं है, तो व्यवहार अपरिभाषित है।
  3. अगर कोड का परीक्षण किया गया तो विनिर्देशन से दूर बदलाव को तोड़ें

मैंने लाइब्रेरी रूटीन के लिए टेस्ट-ड्रिवेन-डेवलपमेंट को बहुत अनुकूल पाया है क्योंकि आप अनिवार्य रूप से एपीआई को पहले लिखते हैं, और वास्तविक कार्यान्वयन को।


7

टीडीडी के लिए, "अच्छा" परीक्षण परीक्षण विशेषताएं हैं जो ग्राहक चाहते हैं ; सुविधाएँ आवश्यक रूप से कार्यों के अनुरूप नहीं होती हैं, और डेवलपर द्वारा वैक्यूम में परिदृश्यों का परीक्षण नहीं किया जाना चाहिए

आपके मामले में - मैं अनुमान लगा रहा हूं - 'सुविधा' यह है कि फिट फ़ंक्शन एक निश्चित त्रुटि सहिष्णुता के भीतर इनपुट डेटा को मॉडल करता है। चूंकि मुझे नहीं पता कि आप वास्तव में क्या कर रहे हैं, मैं कुछ बना रहा हूं; उम्मीद है कि यह अनलकी है।

उदाहरण कहानी:

एक [एक्स-विंग पायलट] के रूप में मैं चाहता हूं कि [0.0001% से अधिक फिट त्रुटि नहीं] ताकि [लक्ष्यीकरण कंप्यूटर एक बॉक्स घाटी के माध्यम से पूरी गति से आगे बढ़ने पर डेथ स्टार के एग्जॉस्ट पोर्ट को हिट कर सके]

तो आप पायलटों से बात करें (और यदि लक्षित हो तो कंप्यूटर को लक्षित करें)। पहले आप बात करें कि is सामान्य ’क्या है, फिर असामान्य के बारे में बात करें। आपको पता चलता है कि इस परिदृश्य में वास्तव में क्या मायने रखता है, क्या सामान्य है, क्या संभावना नहीं है, और क्या केवल संभव है।

मान लें कि सामान्य रूप से आपके पास टेलीमेट्री डेटा के सात चैनलों पर एक आधा सेकंड की विंडो होगी: गति, पिच, रोल, यॉ, लक्ष्य वेक्टर, लक्ष्य आकार, और लक्ष्य वेग, और ये मान निरंतर या रैखिक रूप से बदलते रहेंगे। असामान्य रूप से आपके पास कम चैनल हो सकते हैं और / या मान तेजी से बदल रहे हैं। तो साथ में आप कुछ परीक्षण जैसे:

//Scenario 1 - can you hit the side of a barn?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is zero
    and all other values are constant,
Then:
    the error coefficient must be zero

//Scenario 2 - can you hit a turtle?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is less than c
    and all other values are constant,
Then:
    the error coefficient must be less than 0.0000000001/ns

...

//Scenario 42 - death blossom
Given:
    all 7 channels with 30% dropout and a 0.05 second sampling window
When:
    speed is zero
    and position is within enemy cluster
    and all targets are stationary
Then:
    the error coefficient must be less than 0.000001/ns for each target

अब, आपने देखा होगा कि कहानी में वर्णित विशेष स्थिति के लिए कोई परिदृश्य नहीं है। यह पता चलता है, ग्राहक और अन्य हितधारकों के साथ बात करने के बाद, मूल कहानी में यह लक्ष्य केवल एक काल्पनिक उदाहरण था। वास्तविक परीक्षण आगामी चर्चा से बाहर आए। ऐसा हो सकता है। कहानी को फिर से लिखा जाना चाहिए, लेकिन यह नहीं होना चाहिए [क्योंकि कहानी ग्राहक के साथ बातचीत के लिए सिर्फ एक प्लेसहोल्डर है]।


5

कोने के मामलों के लिए परीक्षण बनाएं, एक परीक्षण सेट की तरह जिसमें केवल न्यूनतम संख्या में इनपुट (संभव 1 या 0) और कुछ मानक मामले हैं। वे यूनिट परीक्षण पूरी तरह से स्वीकृति परीक्षणों के लिए प्रतिस्थापन नहीं हैं, और न ही उन्हें होना चाहिए।


5

मैंने ऐसे बहुत से मामले देखे हैं, जहाँ लोग कोड के लिए परीक्षण लेखन के लिए बहुत अधिक मात्रा में निवेश करते हैं, जो शायद ही कभी दर्ज किया जाता है, और बार-बार दर्ज किए गए कोड के लिए परीक्षण लिखना नहीं।

किसी भी परीक्षण को लिखने के लिए बैठने से पहले, आपको पर्याप्त कवरेज की योजना सुनिश्चित करने के लिए किसी तरह के कॉल ग्राफ को देखना चाहिए।

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


लेकिन बाद की तारीख में क्या होता है जब लाइब्रेरी में बग फिक्स के साथ नया संस्करण होता है?

@ Thorbjørn Ravn Andersen - यह पुस्तकालय पर निर्भर करता है कि क्या बदला है और उनकी अपनी परीक्षण प्रक्रिया। मैं कोड के लिए परीक्षण लिखने नहीं जा रहा हूं जो मुझे पता है कि जब मैं इसे जगह पर गिराता हूं तो काम करता है, और कभी भी स्पर्श नहीं करता है। तो, अगर यह अद्यतन करने के बाद काम करता है, तो मन से बाहर चला जाता है :) बेशक अपवाद हैं।
टिम पोस्ट

यदि आप अपने पुस्तकालय पर निर्भर हैं, तो आप जो कर सकते हैं, वह परीक्षण लिखने के लिए है, जो आपको उम्मीद है कि पुस्तकालय वास्तव में क्या करने के लिए

... और अगर यह बदल गया है, तो लाइब्रेरी कहा जाने वाली चीजों पर परीक्षण ... tl; डॉ; मुझे थर्ड-पार्टी कोड के सराय का परीक्षण करने की आवश्यकता नहीं है। उत्तर स्पष्टता के लिए अद्यतन किया गया है, यद्यपि।
टिम पोस्ट

4

बहुत ज्यादा टीडीडी नहीं है, लेकिन क्यूए में जाने के बाद आप क्यूए प्रक्रिया के दौरान आने वाले किसी भी कीड़े को पुन: उत्पन्न करने के लिए परीक्षण मामलों की स्थापना करके अपने परीक्षणों में सुधार कर सकते हैं। जब आप लंबी अवधि के समर्थन में जा रहे हों तो यह विशेष रूप से मूल्यवान हो सकता है और आप ऐसी जगह पर जाने लगते हैं जहां आप लोगों को अनजाने में पुराने बगों को फिर से शुरू करने का जोखिम उठाते हैं। जगह लेने के लिए एक परीक्षण होना जो विशेष रूप से मूल्यवान है।


3

मेरी कोशिश है कि हर परीक्षा केवल एक ही चीज की परीक्षा हो। मैं प्रत्येक परीक्षा को एक नाम देने की कोशिश करता हूं जैसे कि shouldDoomething ()। मैं व्यवहार का परीक्षण करने की कोशिश करता हूं, कार्यान्वयन नहीं। मैं केवल सार्वजनिक तरीकों का परीक्षण करता हूं।

मेरे पास आम तौर पर सफलता के लिए एक या कुछ परीक्षण होते हैं, और फिर शायद सार्वजनिक पद्धति के अनुसार, असफलता के लिए परीक्षणों की एक मुट्ठी।

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

यदि क्लास ए दूसरे क्लास बी का उपयोग करता है, तो मैं एक इंटरफ़ेस, एक्स, जोड़ूंगा, ताकि ए सीधे बी का उपयोग न करे। तब मैं नकली-अप एक्सकॉक बनाऊंगा और अपने परीक्षणों में बी के बजाय इसका उपयोग करूंगा। यह वास्तव में परीक्षण के निष्पादन में तेजी लाने में मदद करता है, परीक्षण जटिलता को कम करता है, और ए के लिए मेरे द्वारा लिखी जाने वाली परीक्षणों की संख्या को भी कम करता है क्योंकि मुझे बी की विशिष्टताओं के साथ सामना नहीं करना पड़ता है। मैं उदाहरण के लिए परीक्षण कर सकता हूं कि ए कॉल एक्स.थोममेथोड () B.someMethod () को कॉल करने के साइड इफेक्ट के बजाय।

आप टेस्ट कोड को भी साफ रखें।

डेटाबेस परत के रूप में एपीआई का उपयोग करते समय, मैं इसका मजाक उड़ाऊंगा और कमांड पर हर संभव अवसर पर अपवाद को फेंकने के लिए मॉक-अप को सक्षम करूंगा। मैं तब एक फेंकने के बिना परीक्षण चलाता हूं, और एक लूप में, हर बार अगले अवसर पर एक अपवाद को फेंकने तक जब तक कि परीक्षण फिर से नहीं बढ़ता। सिम्बियन के लिए उपलब्ध स्मृति परीक्षणों की तरह एक सा।


2

मैं देख रहा हूं कि एंड्री लोरी पहले ही रॉय ओशेरोव की यूनिट टेस्ट मेट्रिक्स पोस्ट कर चुके हैं; लेकिन ऐसा लगता है कि किसी ने भी (मानार्थ) सेट प्रस्तुत नहीं किया है जो अंकल बॉब क्लीन कोड (132-133) में देता है । वह एफआईआरएस एफआईआर का उपयोग करता है (यहाँ मेरे सारांश के साथ):

  • फास्ट (उन्हें जल्दी से चलना चाहिए, ताकि लोग उन्हें चलाने में बुरा न मानें)
  • स्वतंत्र (परीक्षण एक दूसरे के लिए सेटअप या अशांति नहीं करना चाहिए)
  • दोहराने योग्य (सभी वातावरण / प्लेटफार्मों पर चलना चाहिए)
  • स्व-सत्यापन (पूरी तरह से स्वचालित; आउटपुट "पास" या "विफल" होना चाहिए, लॉग फ़ाइल नहीं)
  • समय पर (जब उन्हें लिखना है - उत्पादन कोड लिखने से ठीक पहले वे परीक्षण करते हैं)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.