multithreading मैं इकाई परीक्षण थ्रेडेड कोड कैसे करना चाहिए?




unit-testing (25)

(यदि संभव हो) धागे का प्रयोग न करें, अभिनेताओं / सक्रिय वस्तुओं का उपयोग करें। परीक्षण करने में आसान है।

https://code.i-harness.com

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

यह आज प्रोग्रामर के लिए वास्तव में एक महत्वपूर्ण समस्या की तरह लगता है, यह हमारे ज्ञान को इस इमो पर पूल करने के लिए उपयोगी होगा।


आप परीक्षण उदाहरण थ्रेडसेफ बनाने के लिए EasyMock.makeThreadSafe का उपयोग कर सकते हैं


आसपास के कुछ उपकरण काफी अच्छे हैं। यहां कुछ जावा वाले का सारांश दिया गया है।

कुछ अच्छे स्थैतिक विश्लेषण उपकरणों में FindBugs (कुछ उपयोगी संकेत देता है), JLint , जावा पाथफाइंडर (जेपीएफ और जेपीएफ 2), और Bogor

MultithreadedTC काफी अच्छा गतिशील विश्लेषण उपकरण है (जुनीट में एकीकृत) जहां आपको अपना खुद का परीक्षण केस स्थापित करना होगा।

आईबीएम रिसर्च से ConTest दिलचस्प है। यह यादृच्छिक रूप से बग को उजागर करने की कोशिश करने के लिए सभी प्रकार के थ्रेड संशोधित व्यवहार (उदाहरण के लिए नींद और उपज) डालने से आपके कोड को नियंत्रित करता है।

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

मल्टीथ्रेडेडटीसी शायद सबसे मुख्यधारा है, लेकिन ऊपर सूचीबद्ध कुछ स्थिर विश्लेषण उपकरण निश्चित रूप से देखने लायक हैं।


जावा के लिए, JCIP अध्याय 12 देखें। कम से कम शुद्धता और समवर्ती कोड के आविष्कारों का परीक्षण करने के लिए निर्धारक, बहु-थ्रेडेड यूनिट परीक्षणों को लिखने के कुछ ठोस उदाहरण हैं।

यूनिट परीक्षणों के साथ "थ्रेड-सुरक्षा" प्रदान करना बहुत ही आसान है। मेरा विश्वास यह है कि विभिन्न प्लेटफॉर्म / कॉन्फ़िगरेशन पर स्वचालित एकीकरण परीक्षण द्वारा यह बेहतर सेवा प्रदान की जाती है।


जावा में: पैकेज java.util.concurrent में कुछ बुरे ज्ञात वर्ग शामिल हैं, जो निर्धारिक जुनीट-टेस्ट लिखने में मदद कर सकते हैं।

अच्छी तरह से देखिए


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

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

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

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

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


देखो, ऐसा करने का कोई आसान तरीका नहीं है। मैं एक परियोजना पर काम कर रहा हूं जो स्वाभाविक रूप से बहुप्रचारित है। घटनाक्रम ऑपरेटिंग सिस्टम से आते हैं और मुझे उन्हें एक साथ संसाधित करना होगा।

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

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

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

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

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


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

छिड़काव - उन्नत सिंक्रनाइज़ेशन ऑब्जेक्ट


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

await().untilCall( to(myService).myMethod(), greaterThan(3) );

या

await().atMost(5,SECONDS).until(fieldIn(myObject).ofType(int.class), equalTo(1));

इसमें स्कैला और ग्रोवी का भी समर्थन है।

await until { something() > 4 } // Scala example

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

उद्धरण:

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

...

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

...

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


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

असल में यह वर्णन करता है कि आप तर्क को अपने पर्यावरण से अलग करने वाले एक अलग, आसान-से-परीक्षण घटक में कैसे निकाल सकते हैं। इस तर्क का परीक्षण करने के बाद, आप जटिल व्यवहार का परीक्षण कर सकते हैं (बहु-थ्रेडिंग, एसिंक्रोनस निष्पादन, आदि ...)


मेरे पास थ्रेडेड कोड का परीक्षण करने का दुर्भाग्यपूर्ण कार्य है और वे निश्चित रूप से सबसे कठिन परीक्षण हैं जिन्हें मैंने कभी लिखा है।

मेरे परीक्षण लिखते समय, मैंने प्रतिनिधियों और घटनाओं के संयोजन का उपयोग किया। असल में यह PropertyNotifyChanged ईवेंट का उपयोग WaitCallback या किसी प्रकार की ConditionalWaiter WaitCallback साथ करने के बारे में है।

मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका था, लेकिन यह मेरे लिए काम किया है।


मेरे संबंधित उत्तर पर एक नज़र डालें

कस्टम बैरियर के लिए एक टेस्ट क्लास डिजाइन करना

यह जावा की ओर पक्षपातपूर्ण है लेकिन विकल्पों का उचित सारांश है।

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

स्टेटिक विश्लेषण और औपचारिक तरीकों (देखें, समवर्ती: राज्य मॉडल और जावा प्रोग्राम ) एक विकल्प है लेकिन मैंने उन्हें वाणिज्यिक विकास में सीमित उपयोग के रूप में पाया है।

यह न भूलें कि किसी भी भार / सोख शैली परीक्षणों को शायद ही कभी समस्याओं को उजागर करने की गारंटी दी जाती है।

सौभाग्य!


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

इसलिए मैंने रैपर लिखे हैं जो इस तरह कुछ दिखते हैं (सरलीकृत):

public interface IThread
{
    void Start();
    ...
}

public class ThreadWrapper : IThread
{
    private readonly Thread _thread;

    public ThreadWrapper(ThreadStart threadStart)
    {
        _thread = new Thread(threadStart);
    }

    public Start()
    {
        _thread.Start();
    }
}

public interface IThreadingManager
{
    IThread CreateThread(ThreadStart threadStart);
}

public class ThreadingManager : IThreadingManager
{
    public IThread CreateThread(ThreadStart threadStart)
    {
         return new ThreadWrapper(threadStart)
    }
}

वहां से मैं आसानी से अपने घटकों में IThreadingManager इंजेक्ट कर सकता हूं और परीक्षण के दौरान अपेक्षा करता हूं कि थ्रेड व्यवहार करने के लिए पसंद के मेरे अलगाव ढांचे का उपयोग करें।

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


मैं समांतर धागे पर निष्पादित करने के लिए दो या अधिक परीक्षण विधियों को लिखना पसंद करता हूं, और उनमें से प्रत्येक परीक्षण के तहत वस्तु में कॉल करता है। मैं अलग-अलग धागे से कॉल के क्रम को समन्वयित करने के लिए स्लीप () कॉल का उपयोग कर रहा हूं, लेकिन यह वास्तव में विश्वसनीय नहीं है। यह भी बहुत धीमा है क्योंकि आपको लंबे समय तक सोना पड़ता है कि समय आमतौर पर काम करता है।

मुझे एक ही समूह से this मिली जिसने FindBugs लिखा था। यह आपको नींद () का उपयोग किये बिना घटनाओं का क्रम निर्दिष्ट करने देता है, और यह विश्वसनीय है। मैंने अभी तक कोशिश नहीं की है।

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

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

अपडेट करें: मैंने मल्टीथ्रेडेड टीसी जावा लाइब्रेरी के साथ थोड़ा सा खेला है, और यह अच्छी तरह से काम करता है। मैंने अपनी कुछ विशेषताओं को एक .NET संस्करण में भी पोर्ट किया है जिसे मैं TickingTest कहता TickingTest


मैंने पिछले हफ्ते एक विश्वविद्यालय पुस्तकालय में समवर्ती कोड की डीबगिंग का अध्ययन किया। केंद्रीय समस्या समवर्ती कोड गैर-निर्धारक है। आम तौर पर, अकादमिक डीबगिंग यहां तीन शिविरों में से एक में गिर गई है:

  1. घटना का पता लगाने / पुनरावृत्ति। इसके लिए एक ईवेंट मॉनीटर की आवश्यकता होती है और फिर भेजे गए ईवेंट की समीक्षा की आवश्यकता होती है। एक यूटी ढांचे में, इसमें परीक्षण के हिस्से के रूप में मैन्युअल रूप से ईवेंट भेजना होगा, और फिर पोस्ट-मॉर्टम समीक्षा करना होगा।
  2. स्क्रिप्ट। यह वह जगह है जहां आप ट्रिगर के सेट के साथ चल रहे कोड से बातचीत करते हैं। "एक्स> foo, baz () पर"। इसका उपयोग यूटी ढांचे में किया जा सकता है जहां आपके पास एक निश्चित शर्त पर एक परीक्षण परीक्षण ट्रिगर करने वाला एक रन-टाइम सिस्टम होता है।
  3. इंटरएक्टिव। यह स्पष्ट रूप से एक स्वचालित परीक्षण स्थिति में काम नहीं करेगा। ;)

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

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

शुभकामनाएं, और समस्या पर काम करते रहें।


मैंने बहुत कुछ किया है, और हाँ यह बेकार है।

कुछ सुझाव:

  • एकाधिक परीक्षण धागे चलाने के लिए GroboUtils
  • अल्फावर्क्स कॉन्टटेस्ट वाद्ययंत्र वर्गों के लिए इंटरटेविंग्स को पुनरावृत्तियों के बीच अलग-अलग करने के कारण
  • एक throwable क्षेत्र बनाएं और इसे tearDown में tearDown (लिस्टिंग 1 देखें)। यदि आप किसी अन्य धागे में खराब अपवाद पकड़ते हैं, तो इसे फेंकने के लिए असाइन करें।
  • मैंने लिस्टिंग 2 में यूटिल क्लास बनाया है और इसे अमूल्य पाया है, विशेष रूप से प्रतीक्षा करेंफॉर सत्यापित करें और प्रतीक्षा करें, जो आपके परीक्षणों के प्रदर्शन को काफी बढ़ाएगा।
  • अपने परीक्षणों में AtomicBoolean का अच्छा उपयोग करें। यह थ्रेड सुरक्षित है, और आपको अक्सर कॉलबैक कक्षाओं से मूल्यों को स्टोर करने के लिए अंतिम संदर्भ प्रकार की आवश्यकता होगी। लिस्टिंग 3 में उदाहरण देखें।
  • हमेशा अपने परीक्षण को एक टाइमआउट (उदाहरण के लिए, @Test(timeout=60*1000) ) देना सुनिश्चित करें, @Test(timeout=60*1000) परीक्षण कभी-कभी टूटने पर हमेशा के लिए लटका सकते हैं

लिस्टिंग 1:

@After
public void tearDown() {
    if ( throwable != null )
        throw throwable;
}

लिस्टिंग 2:

import static org.junit.Assert.fail;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Random;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.time.StopWatch;
import org.easymock.EasyMock;
import org.easymock.classextension.internal.ClassExtensionHelper;
import static org.easymock.classextension.EasyMock.*;

import ca.digitalrapids.io.DRFileUtils;

/**
 * Various utilities for testing
 */
public abstract class DRTestUtils
{
    static private Random random = new Random();

/** Calls {@link #waitForCondition(Integer, Integer, Predicate, String)} with
 * default max wait and check period values.
 */
static public void waitForCondition(Predicate predicate, String errorMessage) 
    throws Throwable
{
    waitForCondition(null, null, predicate, errorMessage);
}

/** Blocks until a condition is true, throwing an {@link AssertionError} if
 * it does not become true during a given max time.
 * @param maxWait_ms max time to wait for true condition. Optional; defaults
 * to 30 * 1000 ms (30 seconds).
 * @param checkPeriod_ms period at which to try the condition. Optional; defaults
 * to 100 ms.
 * @param predicate the condition
 * @param errorMessage message use in the {@link AssertionError}
 * @throws Throwable on {@link AssertionError} or any other exception/error
 */
static public void waitForCondition(Integer maxWait_ms, Integer checkPeriod_ms, 
    Predicate predicate, String errorMessage) throws Throwable 
{
    waitForCondition(maxWait_ms, checkPeriod_ms, predicate, new Closure() {
        public void execute(Object errorMessage)
        {
            fail((String)errorMessage);
        }
    }, errorMessage);
}

/** Blocks until a condition is true, running a closure if
 * it does not become true during a given max time.
 * @param maxWait_ms max time to wait for true condition. Optional; defaults
 * to 30 * 1000 ms (30 seconds).
 * @param checkPeriod_ms period at which to try the condition. Optional; defaults
 * to 100 ms.
 * @param predicate the condition
 * @param closure closure to run
 * @param argument argument for closure
 * @throws Throwable on {@link AssertionError} or any other exception/error
 */
static public void waitForCondition(Integer maxWait_ms, Integer checkPeriod_ms, 
    Predicate predicate, Closure closure, Object argument) throws Throwable 
{
    if ( maxWait_ms == null )
        maxWait_ms = 30 * 1000;
    if ( checkPeriod_ms == null )
        checkPeriod_ms = 100;
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    while ( !predicate.evaluate(null) ) {
        Thread.sleep(checkPeriod_ms);
        if ( stopWatch.getTime() > maxWait_ms ) {
            closure.execute(argument);
        }
    }
}

/** Calls {@link #waitForVerify(Integer, Object)} with <code>null</code>
 * for {@code maxWait_ms}
 */
static public void waitForVerify(Object easyMockProxy)
    throws Throwable
{
    waitForVerify(null, easyMockProxy);
}

/** Repeatedly calls {@link EasyMock#verify(Object[])} until it succeeds, or a
 * max wait time has elapsed.
 * @param maxWait_ms Max wait time. <code>null</code> defaults to 30s.
 * @param easyMockProxy Proxy to call verify on
 * @throws Throwable
 */
static public void waitForVerify(Integer maxWait_ms, Object easyMockProxy)
    throws Throwable
{
    if ( maxWait_ms == null )
        maxWait_ms = 30 * 1000;
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    for(;;) {
        try
        {
            verify(easyMockProxy);
            break;
        }
        catch (AssertionError e)
        {
            if ( stopWatch.getTime() > maxWait_ms )
                throw e;
            Thread.sleep(100);
        }
    }
}

/** Returns a path to a directory in the temp dir with the name of the given
 * class. This is useful for temporary test files.
 * @param aClass test class for which to create dir
 * @return the path
 */
static public String getTestDirPathForTestClass(Object object) 
{

    String filename = object instanceof Class ? 
        ((Class)object).getName() :
        object.getClass().getName();
    return DRFileUtils.getTempDir() + File.separator + 
        filename;
}

static public byte[] createRandomByteArray(int bytesLength)
{
    byte[] sourceBytes = new byte[bytesLength];
    random.nextBytes(sourceBytes);
    return sourceBytes;
}

/** Returns <code>true</code> if the given object is an EasyMock mock object 
 */
static public boolean isEasyMockMock(Object object) {
    try {
        InvocationHandler invocationHandler = Proxy
                .getInvocationHandler(object);
        return invocationHandler.getClass().getName().contains("easymock");
    } catch (IllegalArgumentException e) {
        return false;
    }
}
}

लिस्टिंग 3:

@Test
public void testSomething() {
    final AtomicBoolean called = new AtomicBoolean(false);
    subject.setCallback(new SomeCallback() {
        public void callback(Object arg) {
            // check arg here
            called.set(true);
        }
    });
    subject.run();
    assertTrue(called.get());
}

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

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

यदि आप मल्टीथ्रेडेड जावा लिखते हैं contemplateltd.com/threadsafe


यदि आप सरल नए थ्रेड (रननेबल) का परीक्षण कर रहे हैं । Run () अनुक्रमिक रूप से चलाने योग्य चलाने के लिए आप थ्रेड का नकल कर सकते हैं

उदाहरण के लिए यदि परीक्षण ऑब्जेक्ट का कोड इस तरह के एक नए धागे को आमंत्रित करता है

Class TestedClass{
    public void doAsychOp(){
       new Thread(new myRunnable()).start()
    }

नए थ्रेड का मज़ाक उड़ाते हुए और चलने योग्य तर्क को अनुक्रमिक रूप से चलाने में मदद कर सकते हैं

@Mock
private Thread threadMock;

@Test
public void myTest() throws Exception {
    PowerMockito.mockStatic(Thread.class);
    //when new thread is created execute runnable immediately 
    PowerMockito.whenNew(Thread.class).withAnyArguments().then(new Answer<Thread>() {
        @Override
        public Thread answer(InvocationOnMock invocation) throws Throwable {
                // immediately run the runnable
                Runnable runnable = invocation.getArgumentAt(0, Runnable.class);
                if(runnable != null) {
                    runnable.run();
                }
                return threadMock;//return a mock so Thread.start() will do nothing         
            }
        }); 
       TestedClass testcls = new TestedClass()
       testcls.doAsychOp(); //will invoke myRunnable.run in current thread
      //.... check expected 

यह कुछ समय हो गया है जब यह प्रश्न पोस्ट किया गया था, लेकिन अभी भी इसका उत्तर नहीं दिया गया है ...

kleolb02 का जवाब एक अच्छा है। मैं अधिक जानकारी में जाकर कोशिश करूंगा।

एक तरीका है, जिसे मैं सी # कोड के लिए अभ्यास करता हूं। यूनिट परीक्षणों के लिए आपको पुनरुत्पादित परीक्षण प्रोग्राम करने में सक्षम होना चाहिए, जो मल्टीथ्रेड कोड में सबसे बड़ी चुनौती है। तो मेरा जवाब एक परीक्षण दोहन में एसिंक्रोनस कोड को मजबूर करने की ओर लक्षित है, जो सिंक्रनाइज़ रूप से काम करता है।

यह जेरार्ड मेस्ज़ार्डोस की पुस्तक "xUnit टेस्ट पैटर्न " से एक विचार है और इसे "हम्बल ऑब्जेक्ट" (पृष्ठ 6 9 5) कहा जाता है: आपको कोर लॉजिक कोड और कुछ भी अलग करना होगा जो एक-दूसरे से एसिंक्रोनस कोड की तरह गंध करता है। इसके परिणामस्वरूप कोर लॉजिक के लिए एक वर्ग होगा, जो सिंक्रनाइज़ेशन से काम करता है।

यह आपको सिंक्रोनस तरीके से कोर लॉजिक कोड का परीक्षण करने की स्थिति में डाल देता है। कोर लॉजिक पर आपके द्वारा किए जा रहे कॉल के समय पर आपका पूर्ण नियंत्रण होता है और इस प्रकार पुन: उत्पन्न परीक्षण कर सकते हैं। और कोर लॉजिक और एसिंक्रोनस लॉजिक को अलग करने से यह आपका लाभ है।

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

इसके ऊपर कुछ भी (कक्षाओं के बीच परीक्षण बातचीत) घटक परीक्षण हैं। इस मामले में, यदि आप "विनम्र वस्तु" पैटर्न से चिपके रहते हैं, तो आप समय पर पूर्ण नियंत्रण प्राप्त कर सकते हैं।


वास्तव में मुश्किल है! मेरे (सी ++) यूनिट परीक्षणों में, मैंने इसे समेकित पैटर्न के आधार पर कई श्रेणियों में विभाजित कर दिया है:

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

  2. मॉनिटर ऑब्जेक्ट्स के लिए यूनिट परीक्षण (जो कॉलर्स के नियंत्रण के थ्रेड में सिंक्रनाइज़ किए गए तरीकों को निष्पादित करते हैं) जो सिंक्रनाइज़ किए गए सार्वजनिक एपीआई का पर्दाफाश करते हैं - एपीआई का प्रयोग करने वाले कई नकली धागे को तुरंत चालू करें। उन परिदृश्यों का निर्माण करें जो निष्क्रिय वस्तु की आंतरिक स्थितियों का प्रयोग करते हैं। एक लंबे समय तक चलने वाले परीक्षण को शामिल करें जो मूल रूप से लंबे समय तक कई धागे से इसे बिल्ली से बाहर धड़कता है। यह अवैज्ञानिक है जो मुझे पता है लेकिन यह आत्मविश्वास पैदा करता है।

  3. सक्रिय वस्तुओं के लिए यूनिट परीक्षण (वे जो अपने स्वयं के धागे या नियंत्रण के धागे को समाहित करते हैं) - वर्ग डिजाइन के आधार पर विविधता के साथ ऊपर # 2 के समान। सार्वजनिक एपीआई अवरुद्ध या गैर-अवरुद्ध हो सकता है, कॉलर्स वायदा प्राप्त कर सकते हैं, डेटा कतार में पहुंच सकता है या इसे खाली करने की आवश्यकता है। यहां कई संयोजन संभव हैं; सफेद बॉक्स दूर। परीक्षण के तहत वस्तु को कॉल करने के लिए अभी भी कई नकली धागे की आवश्यकता है।

स्वगत कथन के रूप में:

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


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

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

वैसे, मुझे लगता है कि एमटी कोड का परीक्षण करने के इस पहलू का उल्लेख यहां नहीं किया गया है: उस कोड के आविष्कारों की पहचान करें जिन्हें आप यादृच्छिक रूप से जांच सकते हैं। दुर्भाग्यवश, उन आविष्कारों को ढूंढना भी एक कठिन समस्या है। साथ ही वे निष्पादन के दौरान हर समय पकड़ नहीं सकते हैं, इसलिए आपको निष्पादन बिंदुओं को ढूंढना / लागू करना होगा जहां आप उन्हें सच होने की उम्मीद कर सकते हैं। इस तरह के राज्य में कोड निष्पादन लाने के लिए भी एक कठिन समस्या है (और खुद को समेकित मुद्दों का सामना करना पड़ सकता है। Whew, यह बहुत मुश्किल है!

पढ़ने के लिए कुछ दिलचस्प लिंक:

  • this : एक ढांचा जो कुछ धागे interleavings को मजबूर करने की अनुमति देता है और फिर invariants के लिए जाँच करें
  • जेमॉक ब्लिट्जर : तनाव परीक्षण सिंक्रनाइज़ेशन
  • assertConcurrent : तनाव परीक्षण synronization के जुनीट संस्करण
  • परीक्षण समवर्ती कोड : ब्रूट फोर्स (तनाव परीक्षण) या निर्धारिती के दो प्राथमिक तरीकों का संक्षिप्त अवलोकन (इनवेरिएंट के लिए जा रहा है)

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

टेस्टेबल मल्टीथ्रेड कोड लिखना

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

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

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

मल्टीथ्रेड कोड के लिए यूनिट परीक्षण लिखना

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

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

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

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


पीट गुडलिफ़ के पास थ्रेडेड कोड के यूनिट परीक्षण पर एक श्रृंखला है।

यह मुश्किल है। मैं आसान तरीका निकालता हूं और थ्रेडिंग कोड को वास्तविक परीक्षण से सारणी रखने की कोशिश करता हूं। पीट का जिक्र है कि जिस तरह से मैं करता हूं वह गलत है लेकिन मुझे या तो अलगाव सही मिला है या मैं अभी भाग्यशाली रहा हूं।


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





unit-testing