इकाई परीक्षणों में चक्रीय निर्भरता के साथ संघर्ष


24

मैं बिट वेक्टर की तरह एक सरल विकसित करने के लिए इसका उपयोग करके TDD का अभ्यास करने की कोशिश कर रहा हूं। मैं स्विफ्ट का उपयोग कर रहा हूं, लेकिन यह एक भाषा-अज्ञेय प्रश्न है।

मेरे BitVectorएक है structकि दुकानों के लिए एक एकल UInt64, और प्रस्तुत करता है आप इसे एक संग्रह की तरह व्यवहार देता है कि इस पर एक API। विवरण ज्यादा मायने नहीं रखता है, लेकिन यह बहुत आसान है। उच्च 57 बिट्स स्टोरेज बिट्स हैं, और निचले 6 बिट्स "काउंट" बिट्स हैं, जो आपको बताता है कि वास्तव में कितने स्टोरेज बिट्स एक निहित मूल्य को स्टोर करते हैं।

अब तक, मेरे पास बहुत सरल क्षमताएं हैं:

  1. एक शुरुआती जो खाली बिट वैक्टर का निर्माण करता है
  2. countप्रकार की एक संपत्तिInt
  3. isEmptyप्रकार की एक संपत्तिBool
  4. एक समानता ऑपरेटर ( ==)। NB: यह Object.equals()जावा में मान-समानता ऑपरेटर ऑपरेटर है , जावा में संदर्भ समानता ऑपरेटर नहीं ==

मैं चक्रीय निर्भरता के एक समूह में भाग रहा हूं:

  1. मेरे इनिशलाइज़र का परीक्षण करने वाली इकाई परीक्षण को यह सत्यापित करने की आवश्यकता है कि नवनिर्मित BitVector। ऐसा 3 तरीकों में से एक में कर सकते हैं:

    1. चेक bv.count == 0
    2. चेक bv.isEmpty == true
    3. जांच करे bv == knownEmptyBitVector

    विधि 1 पर निर्भर करता है count, विधि 2 पर निर्भर करता है isEmpty(जो स्वयं पर निर्भर करता है count, इसलिए इसका उपयोग करने का कोई मतलब नहीं है), विधि 3 पर निर्भर करता है ==। किसी भी मामले में, मैं अलगाव में अपने इनिशियलाइज़र का परीक्षण नहीं कर सकता।

  2. के लिए परीक्षण countकी जरूरत है कुछ है, जो अनिवार्य रूप से मेरी प्रारंभकर्ता (रों) परीक्षण पर संचालित करने के लिए

  3. के कार्यान्वयन पर isEmptyनिर्भर करता हैcount

  4. के कार्यान्वयन पर ==निर्भर करता है count

मैं इस समस्या को आंशिक रूप से एक निजी एपीआई पेश करने में सक्षम था BitVectorजो मौजूदा बिट पैटर्न (एक UInt64) से निर्माण करता है । इसने मुझे किसी अन्य इनिशियलाइज़र के परीक्षण के बिना मूल्यों को इनिशियलाइज़ करने की अनुमति दी, ताकि मैं अपने तरीके से "बूट स्ट्रैप" कर सकूं।

मेरी यूनिट परीक्षणों के लिए सही मायने में यूनिट टेस्ट होने के लिए, मैं खुद को हैक्स का एक गुच्छा बनाकर पाता हूं, जो मेरे उत्पादों और परीक्षण कोड को काफी हद तक जटिल करता है।

इस प्रकार के मुद्दों के बारे में आप वास्तव में क्या सोचते हैं?


20
आप "इकाई" शब्द पर बहुत संकीर्ण दृष्टिकोण ले रहे हैं। BitVectorइकाई परीक्षण के लिए एक बिल्कुल ठीक इकाई का आकार है और तुरंत अपने मुद्दों को हल करता है कि BitVectorसार्थक परीक्षण करने के लिए सार्वजनिक सदस्यों को एक-दूसरे की आवश्यकता होती है।
बार्ट वैन इनगेन शेनॉ

आप बहुत अधिक कार्यान्वयन विवरण जानते हैं। क्या आपका विकास वास्तव में परीक्षण- संचालित है ?
हर्बी

@herby नहीं, यही कारण है कि मैं अभ्यास कर रहा हूँ। हालांकि यह वास्तव में एक अप्राप्य मानक जैसा लगता है। मुझे कोई बात नहीं है कि मैंने कभी भी किसी भी स्पष्ट मानसिक सन्निकटन के बिना कुछ भी प्रोग्राम किया है कि कार्यान्वयन क्या होगा।
अलेक्जेंडर - मोनिका

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

जवाबों:


66

आप कार्यान्वयन विवरण के बारे में बहुत अधिक चिंता कर रहे हैं।

इससे कोई फर्क नहीं पड़ता है कि आपके वर्तमान कार्यान्वयन में , (या आपके अन्य जो भी रिश्ते हो सकते हैं) isEmptyपर निर्भर करता है count: आप सभी को सार्वजनिक इंटरफ़ेस के बारे में ध्यान रखना चाहिए। उदाहरण के लिए, आपके तीन परीक्षण हो सकते हैं:

  • यह एक नई आरंभिक वस्तु है count == 0
  • यह एक नई आरंभिक वस्तु है isEmpty == true
  • यह एक नई आरंभिक वस्तु ज्ञात खाली वस्तु के बराबर है।

ये सभी वैध परीक्षण हैं, और विशेष रूप से महत्वपूर्ण हो जाते हैं यदि आप कभी भी अपनी कक्षा के आंतरिक को फिर से भरने का निर्णय लेते हैं ताकि isEmptyएक अलग कार्यान्वयन हो जो भरोसा नहीं करता है count- इसलिए जब तक आपके परीक्षण सभी पास नहीं हो जाते, तब तक आप जानते हैं कि आप फिर से प्रभावित नहीं हुए हैं कुछ भी।

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


6
@Alexander आप इकाई परीक्षण की एक स्पष्ट परिभाषा की जरूरत में एक आदमी की तरह लग रहा है। सबसे अच्छा मुझे पता है कि माइकल
फेदर

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

9
@Alexander "कोड का एक टुकड़ा" एक मनमाना माप है। बस एक वेरिएबल को इनिशियलाइज़ करके आप कई "कोड के टुकड़े" का उपयोग कर रहे हैं। क्या मायने रखता है कि आप एक सह-व्यवहार व्यवहार इकाई का परीक्षण कर रहे हैं जैसा कि आपके द्वारा परिभाषित किया गया है
एंट पी।

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

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

5

इस प्रकार के मुद्दों के बारे में आप वास्तव में क्या सोचते हैं?

आप अपनी सोच को संशोधित करते हैं कि "इकाई परीक्षण" क्या है।

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

व्यवहार में, यह अक्सर दिखता है

// GIVEN
obj = new Object(...)

// THEN
assert object.read(...)

या

// GIVEN
obj = new Object(...)

// WHEN
object.change(...)

// THEN
assert object.read(...)

"यूनिट टेस्ट" शब्दावली - ठीक है, यह बहुत अच्छा नहीं होने का एक लंबा इतिहास है।

मैं उन्हें यूनिट परीक्षण कहता हूं, लेकिन वे यूनिट परीक्षणों की स्वीकृत परिभाषा को बहुत अच्छी तरह से मेल नहीं खाते हैं - केंट बेक, उदाहरण के लिए टेस्ट ड्रिवेन डेवलपमेंट

केंट ने 1994 में एसनिट का पहला संस्करण लिखा था, जोउनीत में बंदरगाह 1998 में था, टीडीडी पुस्तक का पहला मसौदा 2002 की शुरुआत में था। इस भ्रम को फैलने में बहुत समय था।

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

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

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


1

सामान्य तौर पर (भले ही टीडीडी का उपयोग न कर रहे हों) आपको यह दिखावा करते हुए यथासंभव परीक्षण लिखने का प्रयास करना चाहिए कि आपको यह पता नहीं है कि इसे कैसे लागू किया जाता है।

यदि आप वास्तव में TDD कर रहे हैं जो कि पहले से ही होना चाहिए। आपके परीक्षण कार्यक्रम का एक निष्पादन योग्य विनिर्देश हैं।

परीक्षण के नीचे कॉल ग्राफ़ कैसा दिखता है, यह अप्रासंगिक है, जब तक कि परीक्षण स्वयं समझदार और अच्छी तरह से बनाए नहीं होते हैं।

मुझे लगता है कि आपकी समस्या टीडीडी की आपकी समझ है।

मेरी राय में आपकी समस्या यह है कि आप अपने TDD व्यक्तित्व को "मिक्स" कर रहे हैं। आपका "परीक्षण", "कोड", और "रिफ्लेक्टर" व्यक्ति एक दूसरे से पूरी तरह से स्वतंत्र रूप से संचालित होते हैं, आदर्श रूप से। विशेष रूप से आपके कोडिंग और रिफैक्टिंग करने वाले व्यक्तियों के पास हरे रंग को चलाने / रखने के अलावा अन्य परीक्षणों के लिए कोई दायित्व नहीं है।

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

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