2009-07-13 84 views
7

संभावित डुप्लिकेट:
What is unit testing and how do you do it?
What is unit testing?यूनिट परीक्षण क्या है?

मैं स्वीकार करते हैं कि आप में से 95% करने के लिए, यह एक बहुत ही WTF सवाल है।

तो। यूनिट टेस्ट क्या है? मैं समझता हूं कि अनिवार्य रूप से आप परमाणु कार्यक्षमता को अलग करने का प्रयास कर रहे हैं लेकिन कैसे क्या आप इसके लिए परीक्षण करते हैं? यह कब आवश्यक है? यह हास्यास्पद कब है? क्या आप एक उदाहरण दे सकते हैं? (अधिमानतः सी में? मैं ज्यादातर इस साइट पर जावा देवों से इसके बारे में सुनता हूं, तो शायद यह ऑब्जेक्ट ओरिएंटेड भाषाओं के लिए विशिष्ट है? मुझे वास्तव में पता नहीं है।)

मुझे पता है कि कई प्रोग्रामर यूनिट परीक्षण द्वारा धार्मिक रूप से कसम खाता है। यह सब किसके बारे में है?

संपादित करें: इसके अलावा, आप आमतौर पर नए कोड लिखने में समय के लिए यूनिट परीक्षण लिखने का अनुपात क्या करते हैं?

+0

डुप्लिकेट का डुप्लिकेट। "यूनिट टेस्ट क्या है" के लिए बस स्टैक ओवरफ़्लो खोजें और आपके पास महीनों तक चबाने के लिए पर्याप्त होगा। – womp

+0

@womp: मैंने अभी किया और मुझे समान शीर्षक वाले किसी को भी नहीं देखा। –

+2

http://stackoverflow.com/search?q=unit+testing – Nifle

उत्तर

9

मैं उस सी ++ से पहले, जावा से पहले जावा हूं, मैं पूरी तरह से आश्वस्त हूं कि मैंने जो भी काम किया है, मैं अब अनचाहे हूं, मैंने उठाई गई परीक्षण रणनीतियों द्वारा बढ़ाया गया था। परीक्षण को स्किमिंग दर्द होता है।

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

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

मेरे राय:

1)। टेस्ट जिन्हें आसानी से पुन: उपयोग किया जा सकता है, बहुत उपयोगी हैं - देर से रेंगने वाले दोषों का कोई अंत नहीं है। एक डीबगर में बैठे विपरीत परीक्षण में दिमाग-धुंधलापन है।

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

3)। परीक्षण बनाए रखने की लागत है। आम तौर पर यह इसके लायक है, लेकिन उन्हें काम करने के efforrt कम मत समझना।

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

+0

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

0

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

http://en.wikipedia.org/wiki/Unit_testing

+0

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

+0

क्या आपने उस लेख से बाहरी लिंक भी पढ़े? – Nifle

+0

@ निफ्ले हां। फिर, कोई वास्तविक दुनिया अंतर्दृष्टि नहीं। बस सिद्धांत। – Tyler

0

उदाहरण के लिए, यदि आप एक मैट्रिक्स वर्ग है, तो आप एक इकाई परीक्षण की जाँच हो सकता है

मैट्रिक्स एक = मैट्रिक्स (.....); A.inverse() * ए == मैट्रिक्स :: पहचान

1

एक यूनिट परीक्षण सॉफ़्टवेयर का एक और टुकड़ा है जिसे आप लिखते हैं जो वांछित कार्यक्षमता की स्वीकृति के लिए आपका मुख्य कोड व्यायाम करता है।

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

असल में, एक इकाई परीक्षण का परीक्षण स्वयं, परीक्षकों द्वारा किया जाना चाहिए, या जवाब देने के लिए अन्य सावधानीपूर्वक समीक्षा की जानी चाहिए "क्या यह परीक्षण मैं इसे चाहता हूं?"

इकाई परीक्षण में "गिवेन्स" या "इनपुट" का एक सेट होगा, और इन्हें अपेक्षित "आउटपुट" से तुलना करें।

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

यूनिट परीक्षण के लिए एक मानक व्याकरण कोड की एक पंक्ति हो सकती है जो इस तरह दिखती है: Assert.AreEqual(a, b)

इकाई परीक्षण विधि निकाय इनपुट, और एक वास्तविक आउटपुट स्थापित कर सकता है, और इसकी अपेक्षा अपेक्षित आउटपुट से कर सकता है।

HelloWorldExample helloWorld = new HelloWorldExample(); 
string expected = "Hello World!"; 
string actual = helloWorld.GetString(); 

Assert.AreEqual(expected, actual); 

अपने इकाई परीक्षण एक विशेष ढांचे की भाषा में लिखा जाता है (जैसे JUnit, NUnit, आदि), प्रत्येक विधि है जो एक "टेस्ट रन" के भाग के रूप में चिह्नित है के परिणाम हो जाएगा परीक्षण परिणामों के एक सेट में एकत्रित, जैसे विफलताओं के लिए लाल बिंदुओं के एक सुंदर ग्राफ और सफलता के लिए हरे रंग के बिंदु, और/या एक एक्सएमएल फ़ाइल, आदि

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

कहें कि आपने कार इंटरफ़ेस को लागू करना चुना है। कार इंटरफ़ेस इस तरह दिखता है:

interface ICar 
{ 
    public void Accelerate(int delta); 
    public void Decelerate(int delta); 
    public int GetCurrentSpeed(); 
} 

आप वर्ग FordTaurus में कार इंटरफ़ेस को लागू करने के लिए चुन:

class FordTaurus : ICar 
{ 
    private int mySpeed; 
    public Accelerate(int delta) 
    { 
     mySpeed += delta; 
    } 
    public Decelerate(int delta) 
    { 
     mySpeed += delta; 
    } 
    public int GetCurrentSpeed() 
    { 
     return mySpeed; 
    } 
} 

आप एक FordTaurus उनकी गति के लिए कि यह सोचते हैं कर रहे हैं, एक एक नकारात्मक मूल्य से गुजरना होगा। हालांकि, मान लीजिए आप कार इंटरफेस के खिलाफ लिखित इकाई परीक्षण का एक सेट है कि, और वे इस तरह दिखेगा:

public static void TestAcceleration(ICar car) 
{ 
    int oldSpeed = car.GetCurrentSpeed(); 
    car.Accelerate(5); 
    int newSpeed = car.GetCurrentSpeed(); 
    Assert.IsTrue(newSpeed > oldSpeed); 
} 
public static void TestDeceleration(ICar car) 
{ 
    int oldSpeed = car.GetCurrentSpeed(); 
    car.Decelerate(5); 
    int newSpeed = car.GetCurrentSpeed(); 
    Assert.IsTrue(newSpeed < oldSpeed); 
} 

परीक्षण आपको बताता है कि हो सकता है आप कार इंटरफ़ेस गलत तरीके से क्रियान्वित किया है।

+0

क्या आप अपने कोड पर यूनिट परीक्षण करते हैं? आपके द्वारा लिखे गए प्रत्येक फ़ंक्शन के लिए प्रत्येक संभावित पैरामीटर के लिए? नया कोड लिखने में समय व्यतीत करने के लिए यूनिट परीक्षणों को लिखने में समय का अनुपात क्या है? – Tyler

+1

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

+1

नए कोड लिखने के लिए परीक्षण लिखने के समय के अनुपात के प्रश्न का उत्तर देने से संकेत मिलता है कि कोड लिखने के लिए एक विशिष्ट पद्धति को अपनाना है। यदि आप हाईस्कूल में हैं, और केवल अनुभव कोडिंग प्राप्त करना चाहते हैं, तो समझें कि किसी भी पद्धति को अपनाने के लिए समय और योजना की आवश्यकता होती है। यदि आप टीडीडी का अभ्यास करना चाहते हैं, तो इस विषय पर एक पुस्तक प्राप्त करें और अध्याय के अनुसार अध्याय के माध्यम से कार्य करें, एक सप्ताह में कहें (ध्यान दें: मुझे इस विषय पर कौन सी किताबें मौजूद हैं इसका कोई विशेष ज्ञान नहीं है)। खुद से पूछें "मेरा लक्ष्य क्या है?"। यदि आप एक विशेष एपीआई के माध्यम से अपना रास्ता काम कर रहे हैं, तो परीक्षण में गहराई से जवाब नहीं हो सकता है। :-) – maxwellb

1

प्वाइंट:

1) एक इकाई परीक्षण क्या है?

एक यूनिट परीक्षण एक सॉफ्टवेयर परीक्षण है जो सॉफ़्टवेयर की कार्यक्षमता की एक अलग इकाई का परीक्षण करने के लिए डिज़ाइन किया गया है।

2) मैं समझता हूं कि अनिवार्य रूप से आप परमाणु कार्यक्षमता को अलग करने का प्रयास कर रहे हैं लेकिन आप इसके लिए कैसे परीक्षण करते हैं?

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

3) यह कब आवश्यक है?

इस पर बहुत सारी राय है। कुछ कहते हैं कि यह हमेशा जरूरी है, कुछ कहते हैं कि यह पूरी तरह से अनावश्यक है। मैं तर्क दूंगा कि यूनिट परीक्षण के साथ अनुभव वाले अधिकांश डेवलपर्स का कहना है कि यूनिट टेस्ट किसी भी महत्वपूर्ण पथ कोड के लिए जरूरी है जिसमें एक ऐसा डिज़ाइन है जो यूनिट परीक्षण के लिए उपयुक्त है (मुझे पता है कि यह थोड़ा परिपत्र है, लेकिन ऊपर # 2 देखें)।

  1. यह हास्यास्पद कब है? क्या आप एक उदाहरण दे सकते हैं?

आम तौर पर, ओवरटेस्टिंग वह जगह है जहां आप स्पेक्ट्रम के हास्यास्पद अंत में आते हैं। उदाहरण के लिए, यदि आपके पास एक 3 डी वेक्टर क्लास है जिसमें प्रत्येक स्केलर घटकों के लिए एक्सेसर्स हैं, तो प्रत्येक स्केलर एक्सेसर्स के लिए इकाई परीक्षण होने से इनपुट की पूरी श्रृंखला की पुष्टि हो रही है और उनमें से प्रत्येक के लिए मानों को सत्यापित करना थोड़ा सा माना जाएगा कुछ लोगों द्वारा overkill। दूसरी तरफ, यह ध्यान रखना महत्वपूर्ण है कि यहां तक ​​कि उन स्थितियों का परीक्षण करने के लिए भी उपयोगी हो सकता है।

  1. मैं ज्यादातर इस साइट पर जावा देवों से इसके बारे में सुनता हूं, तो शायद यह ऑब्जेक्ट ओरिएंटेड भाषाओं के लिए विशिष्ट है?

नहीं, यह वास्तव में किसी भी सॉफ्टवेयर पर लागू है। यूनिट टेस्ट पद्धति जावा वातावरण के साथ परिपक्वता के लिए आई, लेकिन यह वास्तव में किसी भी भाषा या पर्यावरण के लिए लागू है।

  1. यह सब क्या है?

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

2

सबसे सरल/गैर तकनीकी परिभाषा मैं कोड के कुछ हिस्सों का परीक्षण करने के स्वचालित तरीके के साथ आ सकते हैं ...

मैं इसे का उपयोग करें और इसे प्यार करता हूँ ... लेकिन नहीं धार्मिक, मेरे सबसे गौरवपूर्ण क्षण में से एक यूनिट परीक्षण में एक ब्याज गणना थी जो मैंने बैंक के लिए किया था, बेहद जटिल और मेरे पास केवल एक बग था और उस मामले के लिए कोई इकाई परीक्षण नहीं था ... जैसे ही मैंने मामला जोड़ा और अपना कोड तय किया, यह सही था।

ताकि उदाहरण मैं एक वर्ग कॉल InterestCalculation था लेती हैं और उसे और एक भी सार्वजनिक विधि Calculate() वहाँ तर्क के सभी के लिए गुण था जहां गणना करने के लिए और मैं कहाँ कोशिश करते हैं और एक भी में पूरी बात लिखने के लिए करता है, तो कई कदम विधि और बस मेरा परिणाम जांचें, यह जानने के लिए जबरदस्त होगा कि मेरी बग/कहां कहां है ... इसलिए मैंने गणना के प्रत्येक चरण को लिया और सभी अलग-अलग मामलों के लिए एक निजी विधि और यूनिट टेस्ट/एस बनाया। (कुछ लोग आपको बता देंगे केवल सार्वजनिक तरीकों का परीक्षण करने के लिए, लेकिन इस परिदृश्य में यह मेरे लिए बेहतर काम किया ...) निजी तरीकों में से एक उदाहरण था:

विधि:

/// <summary> 
    /// 
    /// </summary> 
    /// <param name="effectiveDate"></param> 
    /// <param name="lastCouponDate"></param> 
    /// <returns></returns> 
    private Int32 CalculateNumberDaysSinceLastCouponDate(DateTime effectiveDate, DateTime lastCouponDate) 
    { 
     Int32 result = 0; 

     if (lastCouponDate.Month == effectiveDate.Month) 
     { 
      result = this._Parameters.DayCount.GetDayOfMonth(effectiveDate) - lastCouponDate.Day; 
     } 
     else 
     { 
      result = this._Parameters.DayCount.GetNumberOfDaysInMonth(lastCouponDate) 
       - lastCouponDate.Day + effectiveDate.Day; 
     } 

     return result; 
    } 

टेस्ट तरीके:

नोट: मैं उन्हें अलग तरह से अब नाम होता है, संख्या के बजाय मैं मूल रूप से 012 में सारांश रखाविधि का नाम।

/// <summary> 
    ///A test for CalculateNumberDaysSinceLastCouponDate 
    ///</summary> 
    [TestMethod()] 
    [DeploymentItem("WATrust.CAPS.DataAccess.dll")] 
    public void CalculateNumberDaysSinceLastCouponDateTest1() 
    { 
     AccruedInterestCalculationMonthly_Accessor target = new AccruedInterestCalculationMonthly_Accessor(); 
     target._Parameters = new AccruedInterestCalculationMonthlyParameters(); 
     target._Parameters.DayCount = new DayCount(13); 
     DateTime effectiveDate = DateTime.Parse("04/22/2008"); 
     DateTime lastCouponDate = DateTime.Parse("04/15/2008"); 
     int expected = 7; 
     int actual; 

     actual = target.CalculateNumberDaysSinceLastCouponDate(effectiveDate, lastCouponDate); 

     Assert.AreEqual(expected, actual); 

     WriteToConsole(expected, actual); 
    } 

    /// <summary> 
    ///A test for CalculateNumberDaysSinceLastCouponDate 
    ///</summary> 
    [TestMethod()] 
    [DeploymentItem("WATrust.CAPS.DataAccess.dll")] 
    public void CalculateNumberDaysSinceLastCouponDateTest2() 
    { 
     AccruedInterestCalculationMonthly_Accessor target = new AccruedInterestCalculationMonthly_Accessor(); 
     target._Parameters = new AccruedInterestCalculationMonthlyParameters(); 
     target._Parameters.DayCount = new DayCount((Int32) 
      DayCount.DayCountTypes.ThirtyOverThreeSixty); 

     DateTime effectiveDate = DateTime.Parse("04/10/2008"); 
     DateTime lastCouponDate = DateTime.Parse("03/15/2008"); 
     int expected = 25; 
     int actual; 

     actual = target.CalculateNumberDaysSinceLastCouponDate(effectiveDate, lastCouponDate); 

     Assert.AreEqual(expected, actual); 

     WriteToConsole(expected, actual); 
    }    

कहाँ यह हास्यास्पद है?

अच्छी तरह से प्रत्येक के लिए ... आप जितना अधिक करते हैं, आप पाएंगे कि यह कहां उपयोगी है और जहां यह "हास्यास्पद" लगता है लेकिन व्यक्तिगत रूप से, मैं इसका उपयोग अपने डेटाबेस का परीक्षण करने के लिए नहीं करता सबसे कट्टर इकाई परीक्षक ... इस अर्थ में कि मेरे पास डेटाबेस स्कीमा का पुनर्निर्माण करने के लिए एक स्क्रिप्ट है, परीक्षण डेटा के साथ डेटाबेस को दोहराएं, आदि। मैं आमतौर पर अपनी डेटा एक्सेस विधि को कॉल करने के लिए एक यूनिट टेस्ट विधि लिखता हूं और इसे डीबग प्रत्यय के साथ लेबल करता हूं इस तरह: FindLoanNotes_Debug() और मैं System.Diagnostics.Debugger.Break() डाल रहा हूं, इसलिए यदि मैं उन्हें डीबग मोड में चलाता हूं तो मैं मैन्युअल रूप से अपने परिणामों की जांच कर सकता हूं।

1

तो क्या आप उदाहरण चाहते हैं? पिछले सेमेस्टर में मैंने एक कंपाइलर्स कोर्स लिया। इसमें हमें एक रजिस्टर आवंटक लिखना पड़ा। सरल शब्दों में कहें, मेरा कार्यक्रम इस तरह संक्षेप किया जा सकता है:

इनपुट: एक ILOC, एक छद्म विधानसभा भाषा है कि मेरे पाठ्यपुस्तक के लिए बनाया गया था में लिखा फ़ाइल। फ़ाइल में निर्देशों के नाम "आर <number>" हैं। समस्या यह है कि कार्यक्रम जितना आवश्यक हो उतने रजिस्टरों का उपयोग करता है, जो आमतौर पर लक्ष्य मशीन पर रजिस्टरों की संख्या से अधिक होता है।

आउटपुट: आईएलओसी में लिखी गई एक और फाइल। इस बार, निर्देशों को फिर से लिखा जाता है ताकि यह उन रजिस्टरों की सही अधिकतम संख्या का उपयोग कर सके जो अनुमति है।

इस कार्यक्रम को लिखने के लिए, मुझे एक कक्षा बनाना था जो आईएलओसी फ़ाइल को पार्स कर सकता था। मैंने उस वर्ग के लिए परीक्षणों का एक गुच्छा लिखा था। नीचे मेरे परीक्षण हैं (मैं वास्तव में और अधिक था, लेकिन इसे कम करने में मदद करने के लिए उनसे छुटकारा पा लिया। मैंने इसे पढ़ने में आपकी सहायता के लिए कुछ टिप्पणियां भी शामिल की हैं)। मैंने सी ++ में प्रोजेक्ट किया था, इसलिए मैंने Google के सी ++ परीक्षण ढांचे (googletest) का उपयोग here पर किया था।

आपको कोड दिखाने से पहले ... मुझे मूल संरचना के बारे में कुछ कहना है। अनिवार्य रूप से, एक टेस्ट क्लास है। आप टेस्ट क्लास में सामान्य सेटअप सामान का एक गुच्छा डालते हैं। फिर टेस्ट मैक्रोज़ हैं जिन्हें TEST_F कहा जाता है। परीक्षण ढांचा इन पर उठाता है और समझता है कि उन्हें परीक्षण के रूप में चलाने की जरूरत है। प्रत्येक TEST_F में 2 तर्क होते हैं, परीक्षण वर्ग का नाम, और परीक्षण का नाम (जो बहुत वर्णनात्मक होना चाहिए ... इस तरह यदि परीक्षण विफल रहता है, तो आप जानते हैं कि वास्तव में क्या असफल रहा)।आप देखेंगे कि प्रत्येक परीक्षण की संरचना समान है: (1) कुछ प्रारंभिक सामग्री सेट करें, (2) जिस विधि को आप परीक्षण कर रहे हैं उसे चलाएं, (3) आउटपुट सत्यापित करें सही है। जिस तरह से आप जांचते हैं (3) EXPECT_ * जैसे मैक्रोज़ का उपयोग करके है। EXPECT_EQ(expected, result) चेक करता है कि resultexpected के बराबर है। यदि ऐसा नहीं है, तो आपको एक उपयोगी त्रुटि संदेश मिलता है जैसे "परिणाम ब्लाह था, लेकिन ब्लाह की उम्मीद थी"।

यहां कोड है (मुझे आशा है कि यह बहुत भ्रमित नहीं है ... यह निश्चित रूप से एक छोटा या आसान उदाहरण नहीं है, लेकिन यदि आप समय लेते हैं तो आप इसका पालन करने में सक्षम होना चाहिए और इसका सामान्य स्वाद कैसे प्राप्त करना चाहिए काम करता है)।

// Unit tests for the iloc_parser.{h, cc} 

#include <fstream> 
#include <iostream> 
#include <gtest/gtest.h> 
#include <sstream> 
#include <string> 
#include <vector> 

#include "iloc_parser.h" 

using namespace std; 

namespace compilers { 
// Here is my test class 
class IlocParserTest : public testing::Test { 
protected: 
    IlocParserTest() {} 
    virtual ~IlocParserTest() {} 

    virtual void SetUp() { 
    const testing::TestInfo* const test_info = 
     testing::UnitTest::GetInstance()->current_test_info(); 
    test_name_ = test_info->name(); 
    } 

    string test_name_; 
}; 

// Here is a utility function to help me test 
static void ReadFileAsString(const string& filename, string* output) { 
    ifstream in_file(filename.c_str()); 
    stringstream result(""); 
    string temp; 
    while (getline(in_file, temp)) { 
    result << temp << endl; 
    } 
    *output = result.str(); 
} 

// All of these TEST_F things are macros that are part of the test framework I used. 
// Just think of them as test functions. The argument is the name of the test class. 
// The second one is the name of the test (A descriptive name so you know what it is 
// testing). 
TEST_F(IlocParserTest, ReplaceSingleInstanceOfSingleCharWithEmptyString) { 
    string to_replace = "blah,blah"; 
    string to_find = ","; 
    string replace_with = ""; 
    IlocParser::FindAndReplace(to_find, replace_with, &to_replace); 
    EXPECT_EQ("blahblah", to_replace); 
} 

TEST_F(IlocParserTest, ReplaceMultipleInstancesOfSingleCharWithEmptyString) { 
    string to_replace = "blah,blah,blah"; 
    string to_find = ","; 
    string replace_with = ""; 
    IlocParser::FindAndReplace(to_find, replace_with, &to_replace); 
    EXPECT_EQ("blahblahblah", to_replace); 
} 

TEST_F(IlocParserTest, 
     ReplaceMultipleInstancesOfMultipleCharsWithEmptyString) { 
    string to_replace = "blah=>blah=>blah"; 
    string to_find = "=>"; 
    string replace_with = ""; 
    IlocParser::FindAndReplace(to_find, replace_with, &to_replace); 
    EXPECT_EQ("blahblahblah", to_replace); 
} 

// This test was suppsoed to strip out the "r" from register 
// register names in the ILOC code. 
TEST_F(IlocParserTest, StripIlocLineLoadI) { 
    string iloc_line = "loadI\t1028\t=> r11"; 
    IlocParser::StripIlocLine(&iloc_line); 
    EXPECT_EQ("loadI\t1028\t 11", iloc_line); 
} 

// Here I make sure stripping the line works when it has a comment 
TEST_F(IlocParserTest, StripIlocLineSubWithComment) { 
    string iloc_line = "sub\tr12, r10\t=> r13 // Subtract r10 from r12\n"; 
    IlocParser::StripIlocLine(&iloc_line); 
    EXPECT_EQ("sub\t12 10\t 13 ", iloc_line); 
} 


// Here I make sure I can break a line up into the tokens I wanted. 
TEST_F(IlocParserTest, TokenizeIlocLineNormalInstruction) { 
    string iloc_line = "sub\t12 10\t 13\n"; // already stripped 
    vector<string> tokens; 
    IlocParser::TokenizeIlocLine(iloc_line, &tokens); 
    EXPECT_EQ(4, tokens.size()); 
    EXPECT_EQ("sub", tokens[0]); 
    EXPECT_EQ("12", tokens[1]); 
    EXPECT_EQ("10", tokens[2]); 
    EXPECT_EQ("13", tokens[3]); 
} 


// Here I make sure I can create an instruction from the tokens 
TEST_F(IlocParserTest, CreateIlocInstructionLoadI) { 
    vector<string> tokens; 
    tokens.push_back("loadI"); 
    tokens.push_back("1"); 
    tokens.push_back("5"); 
    IlocInstruction instruction(IlocInstruction::NONE); 
    EXPECT_TRUE(IlocParser::CreateIlocInstruction(tokens, 
               &instruction)); 
    EXPECT_EQ(IlocInstruction::LOADI, instruction.op_code()); 
    EXPECT_EQ(2, instruction.num_operands()); 
    IlocInstruction::OperandList::const_iterator it = instruction.begin(); 
    EXPECT_EQ(1, *it); 
    ++it; 
    EXPECT_EQ(5, *it); 
} 

// Making sure the CreateIlocInstruction() method fails when it should. 
TEST_F(IlocParserTest, CreateIlocInstructionFromMisspelledOp) { 
    vector<string> tokens; 
    tokens.push_back("ADD"); 
    tokens.push_back("1"); 
    tokens.push_back("5"); 
    tokens.push_back("2"); 
    IlocInstruction instruction(IlocInstruction::NONE); 
    EXPECT_FALSE(IlocParser::CreateIlocInstruction(tokens, 
              &instruction)); 
    EXPECT_EQ(0, instruction.num_operands()); 
} 

// Make sure creating an empty instruction works because there 
// were times when I would actually have an empty tokens vector. 
TEST_F(IlocParserTest, CreateIlocInstructionFromNoTokens) { 
    // Empty, which happens from a line that is a comment. 
    vector<string> tokens; 
    IlocInstruction instruction(IlocInstruction::NONE); 
    EXPECT_TRUE(IlocParser::CreateIlocInstruction(tokens, 
               &instruction)); 
    EXPECT_EQ(IlocInstruction::NONE, instruction.op_code()); 
    EXPECT_EQ(0, instruction.num_operands()); 
} 

// This was a function that helped me generate actual code 
// that I could output as a line in my output file. 
TEST_F(IlocParserTest, MakeIlocLineFromInstructionAddI) { 
    IlocInstruction instruction(IlocInstruction::ADDI); 
    vector<int> operands; 
    operands.push_back(1); 
    operands.push_back(2); 
    operands.push_back(3); 
    instruction.CopyOperandsFrom(operands); 
    string output; 
    EXPECT_TRUE(IlocParser::MakeIlocLineFromInstruction(instruction, &output)); 
    EXPECT_EQ("addI r1, 2 => r3", output); 
} 

// This test actually glued a bunch of stuff together. It actually 
// read an input file (that was the name of the test) and parsed it 
// I then checked that it parsed it correctly. 
TEST_F(IlocParserTest, ParseIlocFileSimple) { 
    IlocParser parser; 
    vector<IlocInstruction*> lines; 
    EXPECT_TRUE(parser.ParseIlocFile(test_name_, &lines)); 
    EXPECT_EQ(2, lines.size()); 

    // Check first line 
    EXPECT_EQ(IlocInstruction::ADD, lines[0]->op_code()); 
    EXPECT_EQ(3, lines[0]->num_operands()); 
    IlocInstruction::OperandList::const_iterator operand = lines[0]->begin(); 
    EXPECT_EQ(1, *operand); 
    ++operand; 
    EXPECT_EQ(2, *operand); 
    ++operand; 
    EXPECT_EQ(3, *operand); 

    // Check second line 
    EXPECT_EQ(IlocInstruction::LOADI, lines[1]->op_code()); 
    EXPECT_EQ(2, lines[1]->num_operands()); 
    operand = lines[1]->begin(); 
    EXPECT_EQ(5, *operand); 
    ++operand; 
    EXPECT_EQ(10, *operand); 

    // Deallocate memory 
    for (vector<IlocInstruction*>::iterator it = lines.begin(); 
     it != lines.end(); 
     ++it) { 
    delete *it; 
    } 
} 

// This test made sure I generated an output file correctly. 
// I built the file as an in memory representation, and then 
// output it. I had a "golden file" that was supposed to represent 
// the correct output. I compare my output to the golden file to 
// make sure it was correct. 
TEST_F(IlocParserTest, WriteIlocFileSimple) { 
    // Setup instructions 
    IlocInstruction instruction1(IlocInstruction::ADD); 
    vector<int> operands; 
    operands.push_back(1); 
    operands.push_back(2); 
    operands.push_back(3); 
    instruction1.CopyOperandsFrom(operands); 
    operands.clear(); 
    IlocInstruction instruction2(IlocInstruction::LOADI); 
    operands.push_back(17); 
    operands.push_back(10); 
    instruction2.CopyOperandsFrom(operands); 
    operands.clear(); 
    IlocInstruction instruction3(IlocInstruction::OUTPUT); 
    operands.push_back(1024); 
    instruction3.CopyOperandsFrom(operands); 

    // Propogate lines with the instructions 
    vector<IlocInstruction*> lines; 
    lines.push_back(&instruction1); 
    lines.push_back(&instruction2); 
    lines.push_back(&instruction3); 

    // Write out the file 
    string out_filename = test_name_ + "_output"; 
    string golden_filename = test_name_ + "_golden"; 
    IlocParser parser; 
    EXPECT_TRUE(parser.WriteIlocFile(out_filename, lines)); 

    // Read back output file and verify contents are as expected. 
    string golden_file; 
    string out_file; 
    ReadFileAsString(golden_filename, &golden_file); 
    ReadFileAsString(out_filename, &out_file); 
    EXPECT_EQ(golden_file, out_file); 
} 
} // namespace compilers 

int main(int argc, char** argv) { 
    // Boiler plate, test initialization 
    testing::InitGoogleTest(&argc, argv); 
    return RUN_ALL_TESTS(); 
} 

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

लेकिन ... सबसे महत्वपूर्ण !!! परीक्षण वास्तव में आपके कोड में प्रारंभिक बग को पकड़ने के बारे में नहीं है ... यह आपके कोड को गलती से तोड़ने से बचाने के बारे में है। हर बार जब मैंने अपनी इलोकपर्सर कक्षा को दोबारा बदल दिया या बदल दिया, तो मुझे विश्वास था कि मैंने इसे खराब तरीके से नहीं बदला क्योंकि मैं अपने परीक्षण (सेकंड के मामले में) चला सकता था और देख सकता हूं कि सभी कोड अभी भी अपेक्षित काम कर रहे हैं। यह यूनिट परीक्षणों का शानदार उपयोग है।

ऐसा लगता है कि वे बहुत अधिक समय लेते हैं ... लेकिन आखिरकार, वे आपको बग्स को ट्रैक करने में समय बचाते हैं क्योंकि आपने कुछ कोड बदल दिया है और नहीं पता कि क्या हुआ। वे यह सत्यापित करने का एक उपयोगी तरीका हैं कि कोड के छोटे टुकड़े ऐसा कर रहे हैं जो उन्हें करना है, और सही ढंग से।

+0

वाह। इसे एक साथ रखने के लिए धन्यवाद। यह बहुत उपयोगी था। – Tyler

संबंधित मुद्दे