मुझे यूनिट टेस्ट थ्रेडेड कोड कैसे करना चाहिए?


704

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

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


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

जावा में: पैकेज java.util.concurrent में कुछ बुरे ज्ञात वर्ग शामिल हैं, जो नियतात्मक JUnit- टेस्ट लिखने में मदद कर सकते हैं। - पर एक नज़र डालें CountDownLatch - सेमाफोर - एक्सचेंजर
Synox

क्या आप कृपया अपनी पिछली इकाई परीक्षण संबंधित प्रश्न का लिंक प्रदान कर सकते हैं?
एंड्रयू ग्रिम

@Andrew ग्रिम: stackoverflow.com/questions/11060/…
jkp

7
मुझे लगता है कि यह नोट करना महत्वपूर्ण है कि यह प्रश्न 8 साल पुराना है, और इस बीच एप्लिकेशन लाइब्रेरी काफी आगे आ चुकी हैं। "आधुनिक युग" (2016) में बहु-थ्रेडेड विकास मुख्य रूप से एम्बेडेड सिस्टम में आता है। लेकिन अगर आप डेस्कटॉप या फोन ऐप पर काम कर रहे हैं, तो पहले विकल्पों का पता लगाएं। .NET जैसे एप्लिकेशन वातावरण में अब सामान्य मल्टी-थ्रेडिंग परिदृश्यों के 90% को प्रबंधित या बहुत सरल बनाने के लिए उपकरण शामिल हैं। (asnync / प्रतीक्षा, PLinq, IObservable, TPL ...)। मल्टी-थ्रेडेड कोड कठिन है। यदि आप पहिया को सुदृढ़ नहीं करते हैं, तो आपको इसे पीछे नहीं हटाना होगा।
पॉल विलियम्स

जवाबों:


245

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

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

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

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

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

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


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

3
वास्तव में एक इलाज है: सक्रिय वस्तुएं। drdobbs.com/parallel/prefer-using-active-objects-instead-of-n/…
Dill

6
जबकि यह अच्छी सलाह है, मैं अभी भी पूछ रहा हूं, "मैं उन न्यूनतम क्षेत्रों का परीक्षण कैसे कर सकता हूं जहां कई थ्रेड्स की आवश्यकता होती है?"
ब्रायन रेनर

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

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

96

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

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

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

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

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

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

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


1
लेकिन कभी-कभी यदि धागे एक-दूसरे के साथ अच्छी तरह से सहयोग करते हैं, तो क्या कुछ का परीक्षण किया जाना चाहिए, है ना? निश्चित रूप से मैं आपके उत्तर को पढ़ने के बाद मूल तर्क को एसिंक्स भाग से अलग कर दूंगा। लेकिन मैं अभी भी एक काम पर सभी धागे के साथ async इंटरफेस के माध्यम से तर्क का परीक्षण करने जा रहा हूँ कॉलबैक किया गया है।
कॉपरकैश

मल्टी-प्रोसेसर सिस्टम के बारे में क्या?
टेक्नोफाइल

65

वास्तव में एक कठिन! मेरी (C ++) यूनिट परीक्षणों में, मैंने इसे कई श्रेणियों में उपयोग की गई संगणना पैटर्न की रेखाओं के साथ तोड़ दिया है:

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

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

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

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

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


51

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

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

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

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

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

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

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

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

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

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


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

4
कम से कम समझे गए तरीकों में से एक का अद्भुत सारांश। आपका उत्तर वास्तविक अलगाव पर धमाकेदार है जो आमतौर पर अनदेखी करता है।
प्रात:

1
एक दर्जन सेकंड काफी लंबा समय है, भले ही आपके पास केवल उस लंबाई के कुछ सौ परीक्षण हों ...
टोबे स्पाइट

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

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

22

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

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


20

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

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

MultithreadedTC काफी अच्छा डायनामिक विश्लेषण टूल है (JUnit में एकीकृत) जहां आपको अपने स्वयं के परीक्षण मामलों को सेट करना होगा।

आईबीएम रिसर्च का निष्कर्ष दिलचस्प है। यह बेतरतीब ढंग से बग को उजागर करने का प्रयास करने के लिए सभी प्रकार के थ्रेड मॉडिफाइंग व्यवहार (जैसे नींद और उपज) को सम्मिलित करके आपका कोड लिखता है।

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

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


16

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

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

1
वाक्पटुता शानदार है - वास्तव में मैं क्या देख रहा था!
फोर्ज_ 7

14

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

उद्धरण:

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

...

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

...

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


13

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

कुछ सुझाव:

  • कई परीक्षण धागे चलाने के लिए GroboUtils
  • अल्फावर्क्स कन्टेस्ट टू इंस्ट्रूमेंट टू इंस्ट्रूमेंट्स टू इंटरेन्शिएंसींग्स ​​फ़ॉर इटेरेशंस
  • एक throwableफ़ील्ड बनाएं और इसे चेक करें tearDown(सूची 1 देखें)। यदि आप किसी अन्य थ्रेड में एक खराब अपवाद को पकड़ते हैं, तो इसे फेंकने योग्य के लिए असाइन करें।
  • मैंने लिस्टिंग 2 में बर्तन वर्ग बनाया और इसे अमूल्य पाया है, विशेष रूप से WaitForVerify और WaitForCondition, जो आपके परीक्षणों के प्रदर्शन को बढ़ा देगा।
  • AtomicBooleanअपने परीक्षणों में अच्छा उपयोग करें । यह थ्रेड सुरक्षित है, और आपको अक्सर कॉलबैक कक्षाओं और इस तरह के मूल्यों को संग्रहीत करने के लिए एक अंतिम संदर्भ प्रकार की आवश्यकता होगी। सूची 3 में उदाहरण देखें।
  • सुनिश्चित करें कि अपने टेस्ट को हमेशा एक टाइमआउट (जैसे @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());
}

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

12

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

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

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

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

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

लेखक परीक्षण में यादृच्छिकता को संदर्भित करता है। यह क्विकचेक हो सकता है , जिसे कई भाषाओं में पोर्ट किया गया है। आप समवर्ती प्रणाली के लिए इस तरह के परीक्षण पर बात कर सकते हैं
अधिकतम

6

पीट गुडलिफ़ की पिरोया कोड की इकाई परीक्षण पर एक श्रृंखला है ।

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


6
मैंने अब तक प्रकाशित दो लेखों को पढ़ा, और मैंने उन्हें बहुत उपयोगी नहीं पाया। वह सिर्फ ज्यादा ठोस सलाह दिए बिना मुश्किलों के बारे में बात करता है। शायद भविष्य के लेखों में सुधार होगा।
डॉन किर्कबी

6

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

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


6

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

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

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

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

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


5

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

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

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 इंजेक्षन कर सकता हूँ और अपनी पसंद के अलगाव ढांचे का उपयोग करके थ्रेड का व्यवहार कर सकता हूं जैसा कि मैं परीक्षण के दौरान उम्मीद करता हूं।

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


5

मेरे संबंधित उत्तर पर एक नज़र है

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

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

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

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

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

सौभाग्य!


आपको tempus-fugitयहां अपनी लाइब्रेरी का भी उल्लेख करना चाहिए , जो helps write and test concurrent code;)
आइडलोन

4

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

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

यदि आप मल्टीथ्रेडेड लिखते हैं तो जावा इसे एक शॉट देता है।


3

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

स्प्रिंकलर - उन्नत तुल्यकालन वस्तु


3
कृपया यहां बताएं दृष्टिकोण, भविष्य में बाहरी लिंक मृत हो सकते हैं।
ऊऊओ

2

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

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

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

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

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


2

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

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

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


1

"मल्टी-थ्रेडेड" कोड के तहत मान लिया गया था कि कुछ ऐसा है

  • स्टेटफुल और म्यूटेबल
  • और कई सूत्र द्वारा समवर्ती रूप से एक्सेस / संशोधित

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

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

चरण 1. एक ही तुल्यकालन संदर्भ में राज्य को संशोधित करने पर विचार करें।

आज कम्पोज़-सक्षम समवर्ती और एसिंक्रोनस कोड लिखना आसान है जहां IO या अन्य धीमी गति से संचालन को पृष्ठभूमि के लिए लोड किया जाता है, लेकिन साझा स्थिति को अद्यतन किया जाता है और एक सिंक्रनाइज़ेशन संदर्भ में क्वेरी की जाती है। जैसे async / प्रतीक्षा कार्य और .NET में Rx इत्यादि - वे सभी डिज़ाइन द्वारा परीक्षण योग्य हैं, परीक्षण को नियतात्मक बनाने के लिए "वास्तविक" कार्य और अनुसूचियों को प्रतिस्थापित किया जा सकता है (हालांकि यह प्रश्न के दायरे से बाहर है)।

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

चरण 2. यदि एकल सिंक्रनाइज़ेशन संदर्भ पर साझा स्थिति का हेरफेर बिल्कुल संभव नहीं है।

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

नोट: यदि कोड कई वर्गों में बड़ा / फैला हुआ है और बहु-धागा राज्य हेरफेर की आवश्यकता है, तो एक बहुत ही उच्च संभावना है कि डिजाइन अच्छा नहीं है, चरण 1 पर पुनर्विचार करें

चरण 3. यदि यह चरण पूरा हो गया है, तो हमें अपने स्वयं के कस्टम स्टेटफुल थ्रेड-सुरक्षित वर्ग / विधि / इकाई का परीक्षण करने की आवश्यकता है ।

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

अगर मुझे वास्तव में इस तरह के कोड ( अंत में, वास्तविक जवाब ) का परीक्षण करना था , तो मैं नीचे कुछ चीजों की कोशिश करूंगा

  1. गैर-नियतात्मक तनाव परीक्षण। उदाहरण के लिए, 100 थ्रेड एक साथ चलाएं और जांचें कि अंतिम परिणाम सुसंगत है। यह कई उपयोगकर्ताओं के परिदृश्य के उच्च स्तर / एकीकरण परीक्षण के लिए अधिक विशिष्ट है, लेकिन इसका उपयोग इकाई स्तर पर भी किया जा सकता है।

  2. कुछ परीक्षण 'हुक' को उजागर करें, जहां परीक्षण नियतात्मक परिदृश्य बनाने में मदद करने के लिए कुछ कोड को इंजेक्ट कर सकता है जहां एक धागा को दूसरे से पहले ऑपरेशन करना होगा। जैसा कि बदसूरत है, मैं कुछ भी बेहतर नहीं सोच सकता।

  3. थ्रेड को चलाने और विशेष क्रम में संचालन करने के लिए देरी से संचालित परीक्षण। कड़ाई से बोलने वाले ऐसे परीक्षण गैर-निर्धारक भी होते हैं (सिस्टम फ्रीज / स्टॉप-द-वर्ल्ड जीसी संग्रह का एक मौका है जो अन्यथा ऑर्केस्ट्रेटेड देरी को विकृत कर सकता है), यह भी बदसूरत है, लेकिन हुक से बचने की अनुमति देता है।


0

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

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

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

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

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


0

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

लेकिन यहां तक ​​कि इस पुस्तकालय को जावा मेमोरी मॉडल विनिर्देशन के अच्छे ज्ञान की आवश्यकता है ताकि हम यह जान सकें कि हम क्या परीक्षण कर रहे हैं। लेकिन मुझे लगता है कि इस प्रयास का फोकस mircobenchmark है। विशाल व्यावसायिक अनुप्रयोग नहीं।


0

विषय पर एक लेख है, उदाहरण कोड में भाषा के रूप में जंग का उपयोग करते हुए:

https://medium.com/@polyglot_factotum/rust-concurrency-five-easy-pieces-871f1c62906a

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

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

लिंक्ड-इन लेख पूरी तरह से यूनिट-परीक्षणों का उपयोग करके लिखा गया है।


-1

यदि आप सरल नए थ्रेड (रन करने योग्य) का परीक्षण कर रहे हैं .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 
}

-3

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


2
@OMTheEternity हो सकता है लेकिन अभी भी इसका सबसे अच्छा जवाब imo है।
जिल्द

-5

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


यह मल्टीथ्रेड कोड के परीक्षण के सभी संभावित तरीके पर नहीं है। समस्या यह नहीं है कि परीक्षण कोड बहु थ्रेडेड चलता है बल्कि यह कि आप कोड कोड का परीक्षण करते हैं जो आमतौर पर बहु-थ्रेडेड चलता है। और आप सब कुछ दूर सिंक्रनाइज़ नहीं कर सकते क्योंकि तब आप वास्तव में डेटा दौड़ के लिए परीक्षण नहीं करते हैं।
बेनिदि
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.