जब टीडीडी परीक्षणों से नई कार्यक्षमता का पता चलता है तो क्या करना चाहिए जो परीक्षण की आवश्यकता है?


13

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

उदाहरण के लिए, मैं एक बिंदु वर्ग लिख रहा हूं जिसमें एक फ़ंक्शन WillCollideWith ( LineSegment ) है :

public class Point {
    // Point data and constructor ...

    public bool CollidesWithLine(LineSegment lineSegment) {
        Vector PointEndOfMovement = new Vector(Position.X + Velocity.X,
                                               Position.Y + Velocity.Y);
        LineSegment pointPath = new LineSegment(Position, PointEndOfMovement);
        if (lineSegment.Intersects(pointPath)) return true;
        return false;
    }
}

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

मैं सिर्फ कोड है कि पता लगाता है कि की lineSegments इंटरसेक्ट अंदर लिखना चाहिए CollidesWithLine समारोह और refactor यह बाद यह काम कर रहा है? यह इस मामले में काम करेगा क्योंकि मैं लाइनसेक्ट से डेटा एक्सेस कर सकता हूं , लेकिन उन मामलों में क्या होगा जहां उस तरह का डेटा निजी है?

जवाबों:


14

बस अपने परीक्षण और हाल के कोड पर टिप्पणी करें (या एक कड़ी में डाल दें) तो आपने वास्तव में चक्र की शुरुआत में घड़ी वापस कर दी है। फिर LineSegment.Intersects(LineSegment)टेस्ट / कोड / रिफलेक्टर से शुरू करें। जब यह पूरा हो जाए, तो अपने पिछले परीक्षण / कोड (या स्टैश से खींच) को अनचाहे छोड़ दें और चक्र के साथ रखें।


यह अलग कैसे है और फिर इसे अनदेखा करना और बाद में वापस आना?
जोशुआ हैरिस

1
बस छोटे विवरण: रिपोर्ट में कोई अतिरिक्त "मुझे अनदेखा" न करें, और यदि आप स्टैड्स का उपयोग करते हैं, तो कोड 'साफ' मामले से अप्रभेद्य है।
जेवियर

क्या है? क्या संस्करण नियंत्रण जैसा है?
यहोशू हैरिस

1
कुछ वीसीएस इसे एक सुविधा (कम से कम गिट और फॉसिल) के रूप में लागू करते हैं। यह आपको एक परिवर्तन को हटाने की अनुमति देता है लेकिन कुछ समय बाद फिर से लागू करने के लिए इसे सहेजता है। मैन्युअल रूप से करना मुश्किल नहीं है, बस एक अंतर बचाएं और अंतिम स्थिति में वापस लौटें। बाद में आप फिर से अलग हो जाते हैं और चालू रहते हैं।
जेवियर

6

TDD चक्र पर:

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

अपने वर्तमान डिजाइन समाधान पर

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

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

इसलिए यह जिम्मेदारी एक अन्य वर्ग के पास होनी चाहिए, उदाहरण के लिए "प्वाइंटसेलेक्शन कॉलिजनडेक्टर" जो एक विधि होगी:

बूल आरोहण (प्वाइंट पी, सेगमेंट एस)

और यह कुछ ऐसा है जिसे आप पॉइंट्स और सेगमेंट से अलग से परखेंगे।

उस डिजाइन के साथ अच्छी बात यह है कि अब आप अपने टक्कर डिटेक्टर के विभिन्न कार्यान्वयन कर सकते हैं। इसलिए उदाहरण के लिए अपने गेम इंजन को बेंचमार्क करना आसान होगा (मुझे लगता है कि आप एक गेम लिख रहे हैं: पी) रनटाइम पर अपनी टक्कर का पता लगाने का तरीका बदलकर। या विभिन्न टक्कर का पता लगाने की रणनीतियों के बीच रनटाइम पर कुछ दृश्य जांच / प्रयोग करना।

फिलहाल, इस तर्क को अपने बिंदु वर्ग में रखकर, आप चीजों को बंद कर रहे हैं और बिंदु वर्ग पर बहुत अधिक जिम्मेदारी को आगे बढ़ा रहे हैं।

आशा है कि यह समझ में आता है,


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

2

TDD फैशन में सबसे आसान काम यह होगा कि आप LineSegment के लिए एक इंटरफ़ेस निकालें और इंटरफ़ेस में लेने के लिए अपने तरीके के पैरामीटर को बदलें। तब आप इनपुट लाइन सेगमेंट और कोड को स्वतंत्र रूप से इंट्रक्ट विधि का परीक्षण कर सकते हैं।


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

0

JUnit4 के साथ आप उन @Ignoreपरीक्षणों के लिए एनोटेशन का उपयोग कर सकते हैं जिन्हें आप स्थगित करना चाहते हैं।

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

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