क्या यूनिट परीक्षणों में डुप्लिकेट कोड अधिक सहनीय है?


113

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

क्या आप सहमत हैं कि यह व्यापार बंद है? यदि हां, तो क्या आप अपने परीक्षण को पठनीय या अनुरक्षणीय बनाना पसंद करते हैं?

जवाबों:


68

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

यदि दोहराव सेट अप में है, तो setUpविधि का अधिक उपयोग करने या अधिक (या अधिक लचीली) निर्माण विधियों को प्रदान करने पर विचार करें ।

यदि दोहराव SUT में हेरफेर करने वाले कोड में है, तो अपने आप से पूछें कि कई तथाकथित "यूनिट" परीक्षण सटीक कार्यक्षमता का उपयोग क्यों कर रहे हैं।

यदि दोहराव मुखर है, तो शायद आपको कुछ कस्टम अभिकथन की आवश्यकता है । उदाहरण के लिए, यदि कई परीक्षणों में जोर दिया गया है जैसे:

assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())

फिर शायद आपको एक ही assertPersonEqualविधि की आवश्यकता है , ताकि आप लिख सकें assertPersonEqual(Person('Joe', 'Bloggs', 23), person)। (या शायद आपको बस समानता ऑपरेटर को अधिभारित करने की आवश्यकता है Person।)

जैसा कि आप उल्लेख करते हैं, परीक्षण कोड को पठनीय होना जरूरी है। विशेष रूप से, यह महत्वपूर्ण है कि परीक्षण का इरादा स्पष्ट हो। मुझे लगता है कि अगर कई परीक्षण अधिकतर समान दिखते हैं, (उदाहरण के लिए तीन-चौथाई रेखाएँ समान या वस्तुतः समान) तो ध्यान से पढ़ने और उनकी तुलना किए बिना महत्वपूर्ण अंतरों को पहचानना और पहचानना कठिन है। इसलिए मुझे लगता है कि दोहराव को हटाने के लिए रीफैक्टरिंग से पठनीयता में मदद मिलती है, क्योंकि परीक्षण के उद्देश्य के लिए हर परीक्षण पद्धति की प्रत्येक पंक्ति सीधे प्रासंगिक है। पाठक के लिए यह अधिक उपयोगी है कि लाइनों का एक यादृच्छिक संयोजन जो सीधे प्रासंगिक है, और लाइनें जो केवल बॉयलरप्लेट हैं।

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


30
"डुप्लिकेटेड कोड यूनिट टेस्ट कोड में एक गंध है जितना कि अन्य कोड में।" नहीं, "यदि आपने परीक्षणों में कोड को डुप्लिकेट किया है, तो कार्यान्वयन कोड को फिर से भरना कठिन हो जाता है क्योंकि आपके पास अपडेट करने के लिए परीक्षणों की अनुपातहीन संख्या है।" ऐसा इसलिए होता है क्योंकि आप सार्वजनिक API के बजाय निजी API का परीक्षण कर रहे हैं।

15
लेकिन यूनिट परीक्षणों में डुप्लिकेट कोड को रोकने के लिए आपको आमतौर पर नए तर्क पेश करने की आवश्यकता होती है। मुझे नहीं लगता कि इकाई परीक्षणों में तर्क होना चाहिए क्योंकि तब आपको इकाई परीक्षणों की इकाई परीक्षणों की आवश्यकता होगी।
पेट्र पेलर

@ user11617 कृपया "निजी एपीआई" और "सार्वजनिक आपी" को परिभाषित करें। मेरी समझ में, सार्वजनिक Api वह Api है जो बाहरी दुनिया / तीसरी पार्टी के उपभोक्ताओं को दिखाई देती है और स्पष्ट रूप से SemVer या समान के माध्यम से दिखाई देती है, और कुछ भी निजी है। इस परिभाषा के साथ लगभग सभी यूनिट परीक्षण "निजी एपीआई" का परीक्षण कर रहे हैं और इसलिए कोड दोहराव के लिए अधिक संवेदनशील है, जो मुझे लगता है कि यह सच है।
कोला

@ कोलकाता "पब्लिक" का मतलब 3 पार्टी उपभोक्ताओं से नहीं है - यह एक वेब एपीआई नहीं है। एक वर्ग का सार्वजनिक एपीआई उन तरीकों को संदर्भित करता है जो क्लाइंट कोड द्वारा उपयोग किए जाने वाले हैं (जो आमतौर पर इतना नहीं बदलते / नहीं होना चाहिए) - आम तौर पर "सार्वजनिक" तरीके। निजी एपीआई तर्क और तरीकों को संदर्भित करता है जो आंतरिक रूप से उपयोग किए जाते हैं। इन्हें कक्षा के बाहर से एक्सेस नहीं किया जाना चाहिए। यह एक कारण है कि एक्सेस मॉडिफायर या भाषा में कन्वेंशन का उपयोग करने वाले वर्ग में तर्क को सही ढंग से एनकैप करना महत्वपूर्ण है।
नाथन

@ किसी भी लाइब्रेरी / dll / nuget पैकेज में 3 पार्टी उपभोक्ता हैं, इसके लिए वेब एप होना जरूरी नहीं है। मैंने जो उल्लेख किया है, वह यह है कि सार्वजनिक वर्गों और सदस्यों की घोषणा करना बहुत ही सामान्य है, जिनका उपयोग सीधे पुस्तकालय उपभोक्ताओं द्वारा नहीं किया जाना चाहिए (या सर्वोत्तम रूप से उन्हें आंतरिक और एन्टेट असेंबली विद इंटरनैटलविट्यूटऑटवर्ट) केवल यूनिट परीक्षणों को सीधे उन तक पहुंचने की अनुमति देने के लिए। यह परीक्षणों के ढेर को लागू करता है और इसे लागू करने से अधिक बोझ बन जाता है
KolA

186

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

हालाँकि, नकल को समाप्त करना आमतौर पर एक अच्छी बात है, जब तक कि यह कुछ भी अस्पष्ट नहीं करता है, और आपके परीक्षणों में दोहराव को समाप्त करने से बेहतर एपीआई हो सकता है। बस सुनिश्चित करें कि आप कम रिटर्न के बिंदु से आगे नहीं जाते हैं।


xUnit और अन्य के पास मुखर कॉल में एक 'संदेश' तर्क है। देवों को जल्दी से असफल परीक्षा परिणाम खोजने की अनुमति देने के लिए सार्थक वाक्यांश लगाने का अच्छा विचार है।
सीलैंड

1
@seand आप यह समझाने की कोशिश कर सकते हैं कि आपका मुखर क्या जाँच कर रहा है, लेकिन जब यह विफल हो रहा है और इसमें कुछ अस्पष्ट कोड हैं, तो डेवलपर को कहीं भी जाकर इसे खोलना होगा। IMO वहां पर आत्म-वर्णन करने के लिए कोड होना अधिक महत्वपूर्ण है।
इगोर

1
@ क्रिस्टोफर, यह पोस्ट सामुदायिक विकी क्यों है?
23

@ स्पेसर मुझे नहीं पता। वहाँ चीजों के बारे में जटिल नियम हुआ करते थे जो स्वचालित रूप से सामुदायिक विकि बन जाते थे।
क्रिस्टोफर जॉनसन

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

47

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

कार्यान्वयन कोड में डुप्लिकेटेड कोड या संरचना हमेशा एक गंध होती है। जब आपको कार्यान्वयन में बॉयलरप्लेट होने लगते हैं, तो आपको अपने अमूर्त को संशोधित करने की आवश्यकता होती है।

दूसरी ओर, परीक्षण कोड को दोहराव का स्तर बनाए रखना चाहिए। परीक्षण कोड में दोहराव से दो लक्ष्य प्राप्त होते हैं:

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

मैं परीक्षण कोड में तुच्छ दोहराव को अनदेखा करता हूं जब तक कि प्रत्येक परीक्षण विधि लगभग 20 लाइनों से कम न हो जाए। मुझे पसंद है जब परीक्षण विधियों में सेटअप-रन-सत्यापित ताल स्पष्ट है।

जब दोहराव परीक्षणों के "सत्यापित" भाग में रेंगता है, तो अक्सर कस्टम अभिकथन विधियों को परिभाषित करना फायदेमंद होता है। बेशक, उन तरीकों को अभी भी स्पष्ट रूप से पहचाने गए संबंध का परीक्षण करना चाहिए जिसे विधि के नाम में स्पष्ट किया जा सकता है: assertPegFitsInHole-> अच्छा, assertPegIsGood-> बुरा।

जब परीक्षण के तरीके लंबे और दोहराव से बढ़ते हैं तो मुझे कभी-कभी कुछ मापदंडों को लेने वाले फिल-इन-द-ब्लक्स टेस्ट टेम्प्लेट को परिभाषित करने के लिए उपयोगी लगता है। फिर वास्तविक परीक्षण विधियों को उचित मापदंडों के साथ टेम्पलेट विधि के लिए एक कॉल के लिए कम किया जाता है।

प्रोग्रामिंग और परीक्षण में बहुत सी चीजों के लिए, कोई स्पष्ट जवाब नहीं है। आपको एक स्वाद विकसित करने की आवश्यकता है, और ऐसा करने का सबसे अच्छा तरीका गलतियाँ करना है।


8

मैं सहमत हूँ। व्यापार बंद मौजूद है, लेकिन विभिन्न स्थानों में अलग है।

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


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

8

आप परीक्षण उपयोगिता विधियों के कई अलग-अलग स्वादों का उपयोग करके पुनरावृत्ति को कम कर सकते हैं ।

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


6

जे फील्ड्स ने वाक्यांश को गढ़ा कि "DSLs DAMP होना चाहिए, DRY नहीं", जहाँ DAMP का अर्थ होता है वर्णनात्मक और सार्थक वाक्यांश । मुझे लगता है कि परीक्षणों पर भी यही बात लागू होती है। जाहिर है, बहुत अधिक नकल खराब है। लेकिन हर कीमत पर नकल निकालना और भी बुरा है। टेस्ट में आशय-प्रकट विनिर्देशों के रूप में कार्य करना चाहिए। यदि, उदाहरण के लिए, आप एक ही विशेषता को कई अलग-अलग कोणों से निर्दिष्ट करते हैं, तो एक निश्चित मात्रा में दोहराव की उम्मीद की जाती है।


3

मैं इस वजह से प्यार करता हूँ:

इसमें मदद करने के लिए 2 चीजें हैं -

  • साझा व्यवहार के परीक्षण के लिए साझा उदाहरण समूह।
    आप परीक्षणों के एक सेट को परिभाषित कर सकते हैं, फिर अपने वास्तविक परीक्षणों में उस सेट को 'शामिल' कर सकते हैं।

  • नेस्टेड संदर्भ।
    आप अनिवार्य रूप से अपने परीक्षणों के एक विशिष्ट सबसेट के लिए एक 'सेटअप' और 'टियरडाउन' विधि रख सकते हैं, न कि केवल कक्षा में हर एक के लिए।

जितनी जल्दी .NET / Java / अन्य परीक्षण ढांचे इन तरीकों को अपनाते हैं, उतना ही बेहतर (या आप अपने परीक्षण लिखने के लिए IronRuby या JRuby का उपयोग कर सकते हैं, जो मुझे व्यक्तिगत रूप से बेहतर विकल्प लगता है)


3

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

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

परीक्षण करते समय अमूर्त के सही स्तर का पता लगाना मुश्किल हो सकता है और मुझे लगता है कि यह करने योग्य है।


2

मुझे नहीं लगता कि अधिक डुप्लिकेट और पठनीय कोड के बीच कोई संबंध है। मुझे लगता है कि आपका टेस्ट कोड आपके अन्य कोड जितना अच्छा होना चाहिए। नॉन-रिपीटिंग कोड अधिक पठनीय होता है और फिर अच्छा होने पर डुप्लिकेट कोड।


2

आदर्श रूप से, यूनिट परीक्षणों को एक बार बदलने के बाद उन्हें नहीं लिखा जाना चाहिए ताकि मैं पठनीयता की ओर झुक जाऊं।

इकाई परीक्षण होने से जितना संभव हो उतना असतत होना चाहिए कि वे उन विशिष्ट कार्यक्षमता पर ध्यान केंद्रित करने में मदद करते हैं जो उन्हें लक्षित कर रहे हैं।

उस के साथ, मैं कोशिश करता हूं और कोड के कुछ टुकड़ों का पुन: उपयोग करता हूं, जिन्हें मैं सेटअप कोड जैसे ओवर-ओवर का उपयोग करके हवा देता हूं, जो कि परीक्षण के एक सेट के बिल्कुल समान है।


2

"उन्हें अधिक डीआरवाई बनाने के लिए फिर से तैयार किया - प्रत्येक परीक्षण का इरादा अब स्पष्ट नहीं था"

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

यही कारण है कि परीक्षण यूनिटटेस्ट का एक उपवर्ग हैं - इसलिए आप अच्छे परीक्षण सूट डिजाइन कर सकते हैं जो सही, आसान और स्पष्ट हैं।

पुराने समय में हमारे पास परीक्षण उपकरण थे जो विभिन्न प्रोग्रामिंग भाषाओं का उपयोग करते थे। परीक्षणों के साथ सुखद, आसान-से-डिज़ाइन तैयार करना कठिन (या असंभव) था।

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

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