टीडीडी और रिफैक्टरिंग के साथ कठिनाइयाँ (या - यह अधिक दर्दनाक क्यों होना चाहिए?)


20

मैं खुद को TDD दृष्टिकोण का उपयोग करना सिखाना चाहता था और मेरे पास एक परियोजना थी जिसे मैं थोड़ी देर के लिए काम करना चाहता था। यह एक बड़ी परियोजना नहीं थी इसलिए मुझे लगा कि यह टीडीडी के लिए एक अच्छा उम्मीदवार होगा। हालांकि, मुझे लगता है कि कुछ गड़बड़ हो गई है। मुझे एक उदाहरण देने दें:

उच्च स्तर पर मेरी परियोजना Microsoft OneNote के लिए एक ऐड-इन है जो मुझे प्रोजेक्ट्स को अधिक आसानी से ट्रैक और प्रबंधित करने की अनुमति देगा। अब, मैं इसके लिए व्यावसायिक तर्क भी रखना चाहता था क्योंकि OneNote से डिक्लेयुड होने की स्थिति में मैंने अपने कस्टम स्टोरेज का निर्माण करने का निर्णय लिया और किसी दिन वापस समाप्त कर दिया।

पहले मैंने एक बुनियादी सादे शब्दों को स्वीकार करने के लिए परीक्षण शुरू किया, जिसमें मैं यह बताना चाहता था कि मैं अपनी पहली विशेषता क्या करना चाहता हूं। यह कुछ इस तरह दिखता है (संक्षिप्तता के लिए इसे नीचे खींचना):

  1. उपयोगकर्ता क्लिक परियोजना बनाते हैं
  2. परियोजना के शीर्षक में उपयोगकर्ता प्रकार
  3. सत्यापित करें कि प्रोजेक्ट सही तरीके से बनाया गया है

UI सामान और कुछ मध्यस्थ योजना पर स्किप करना, मैं अपनी पहली इकाई परीक्षण के लिए आता हूं:

[TestMethod]
public void CreateProject_BasicParameters_ProjectIsValid()
{
    var testController = new Controller();
    Project newProject = testController(A.Dummy<String>());
    Assert.IsNotNull(newProject);
}

अब तक सब ठीक है। लाल, हरा, रिफलेक्टर, आदि। अब यह वास्तव में सामान को बचाने की जरूरत है। यहाँ कुछ कदम काटकर मैं इसके साथ हवा हूँ।

[TestMethod]
public void CreateProject_BasicParameters_ProjectMatchesExpected()
{
    var fakeDataStore = A.Fake<IDataStore>();
    var testController = new Controller(fakeDataStore);
    String expectedTitle = fixture.Create<String>("Title");
    Project newProject = testController(expectedTitle);

    Assert.AreEqual(expectedTitle, newProject.Title);
}

मैं अभी भी इस बिंदु पर अच्छा महसूस कर रहा हूं। मेरे पास अभी तक एक ठोस डेटा स्टोर नहीं है, लेकिन मैंने इंटरफ़ेस बनाया कि मैं यह कैसे अनुमान लगाऊंगा।

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

[TestMethod]
public void SaveNewProject_BasicParameters_RequestsNewPage()
{
    /* snip init code */
    testDataStore.SaveNewProject(A.Dummy<IProject>());
    A.CallTo(() => oneNoteInterop.SavePage()).MustHaveHappened();
}

यह तब तक अच्छा था जब तक मैंने इसे लागू करने की कोशिश नहीं की:

public String SaveNewProject(IProject project)
{
    Page projectPage = oneNoteInterop.CreatePage(...);
}

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

क्या कोई मुझे समझा सकता है अगर मैंने इस प्रक्रिया में कुछ गलत किया हो? वहाँ वैसे भी इस तरह के refactoring से बचा जा सकता है? या यह आम है? यदि यह आम है तो क्या इसे और अधिक दर्द रहित बनाने के तरीके हैं?

सबको शुक्रीया!


यदि आप इस विषय को इस चर्चा मंच पर पोस्ट करेंगे तो आपको कुछ बहुत ही आनंददायक टिप्पणियाँ मिलेंगी: group.google.com/forum/# ​​-forum/… जो विशेष रूप से TDD विषयों के लिए है।
चक क्रुत्सिंगर

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

जवाबों:


19

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

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

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

  2. अपने परीक्षण कोड में दोहराव को कम से कम करें, जैसे आप उत्पादन कोड में करेंगे। यह पोस्ट एक अच्छा संदर्भ है। आपके उदाहरण में, ऐसा लगता है कि IDसंपत्ति को अपने निर्माता से जोड़ना दर्दनाक था क्योंकि आपने कई अलग-अलग परीक्षणों में सीधे निर्माणकर्ता को आमंत्रित किया था। इसके बजाय, ऑब्जेक्ट के निर्माण को एक विधि में निकालने का प्रयास करें या एक परीक्षण इनिशियलाइज़ विधि में प्रत्येक टेस्ट के लिए एक बार इसे इनिशियलाइज़ करें।


मैंने राज्य-आधारित बनाम इंटरैक्शन-आधारित की खूबियों को पढ़ा है और इसे ज्यादातर समय समझता हूं। हालांकि, मैं यह नहीं देखता कि परीक्षण के लिए गुणों को उजागर किए बिना हर मामले में यह कैसे संभव है। ऊपर मेरा उदाहरण लें। मुझे यकीन नहीं है कि कैसे जांचना है कि वास्तव में डेटास्टॉर को "मस्टेवीन क्वीनकल्ड" के लिए एक जोर का उपयोग किए बिना कहा गया था। बिंदु 2 के लिए, आप बिल्कुल सही हैं। मैंने सभी संपादनों के बाद ऐसा किया है, लेकिन मैं सिर्फ यह सुनिश्चित करना चाहता था कि मेरा दृष्टिकोण आमतौर पर स्वीकृत TDD प्रथाओं के अनुरूप था। धन्यवाद!
लैंडन

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

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

@jhewlett यही निष्कर्ष मैं यहाँ तक पहुँचा हूँ। धन्यवाद!
लैंडन

@Hbas क्वेरी करने के लिए कोई डेटाबेस नहीं है। मैं सहमत हूं कि अगर मेरे पास एक होने के लिए सबसे सीधा आगे रास्ता होगा, लेकिन मैं इसे OneNote नोटबुक में जोड़ रहा हूं। इसके बजाय मैं जो सबसे अच्छा कर सकता हूं वह यह है कि पेज को खींचने की कोशिश करने के लिए मेरी इंटरॉप हेल्पर क्लास में एक मेथड जोड़ें। मैं ऐसा करने के लिए परीक्षण लिखता हूं, लेकिन मुझे ऐसा लगा कि मैं एक ही बार में दो चीजों का परीक्षण करूंगा: क्या मैंने इसे बचाया है? और क्या मेरा सहायक वर्ग पृष्ठों को सही ढंग से पुनः प्राप्त करता है? हालाँकि, मुझे लगता है कि कुछ बिंदुओं पर आपके परीक्षणों को अन्य कोड पर भरोसा करना पड़ सकता है जो कहीं और परीक्षण किए गए हैं। धन्यवाद!
लैंडन

10

... मैं मदद नहीं कर सकता, लेकिन ऐसा महसूस कर सकता हूं कि मैंने इस तेज को पकड़ लिया होता अगर मैं डिजाइन को समय से पहले स्केडेड कर देता, बजाय इसके कि इसे TDD प्रॉसेस के दौरान डिजाइन किया जाए ...

शायद शायद नहीं

एक तरफ, टीडीडी ने ठीक काम किया, आपको स्वचालित परीक्षण दिया, जैसा कि आपने कार्यक्षमता का निर्माण किया, और जब आपको इंटरफ़ेस बदलना पड़ा तो तुरंत टूट गया।

दूसरी ओर, शायद अगर आपने निचले-स्तर की सुविधा (CreateProject) के बजाय उच्च-स्तरीय सुविधा (SaveProject) के साथ शुरू किया था, तो आपने जल्द ही लापता मापदंडों को देखा होगा।

तो फिर, शायद तुम नहीं होगा। यह एक अप्राप्य प्रयोग है।

लेकिन अगर आप अगली बार किसी पाठ की तलाश कर रहे हैं: शीर्ष पर शुरू करें। और डिज़ाइन के बारे में उतना ही सोचें जितना आप चाहते हैं।


0

https://frontendmasters.com/courses/angularjs-and-code-testability/ लगभग 2:22:00 बजे से अंत तक (लगभग 1 घंटे)। क्षमा करें कि वीडियो मुफ़्त नहीं है, लेकिन मुझे ऐसा मुफ़्त नहीं मिला है जो इसे इतनी अच्छी तरह से समझाए।

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

जादू कोड टेस्ट लिखने के बजाय टेस्टेबल कोड लिखने में है। यह कोड लिखने के बारे में नहीं है जो एक उपयोगकर्ता होने का दिखावा करता है।

उन्होंने यह भी परीक्षण परख के रूप में कल्पना लिखने के लिए कुछ समय खर्च करता है।

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