2010-06-21 20 views
6

हाल ही में, मैंने स्टैक ओवरव्लो पर एक प्रश्न पूछा (और उत्तर दिया) कि एक इकाई परीक्षण स्वयं द्वारा चलाए जाने पर क्यों काम करेगा और फिर यूनिट परीक्षणों के पूरे बैच के साथ चलने पर स्पोरैडिक रूप से विफल हो जाएगा। यहां देखें: SQL Server and TransactionScope (with MSDTC): Sporadically can't get connectionकचरा कलेक्टर यूनिट परीक्षणों के साथ कैसे काम करता है?

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

मुझे पता चला कि संसाधन संसाधन का थोड़ा सा हिस्सा है। एक SQL सर्वर से कनेक्शन को रिहा करने के लिए एक सूक्ष्म त्रुटि के कारण, मैं कनेक्शन से बाहर चला रहा था और परीक्षण विफल रहे थे। AFAIK, यह लगभग एक स्मृति रिसाव की तरह काम करता है; कनेक्शन को कनेक्शन पूल से आवंटित किया जाता है और कभी भी मुक्त नहीं किया जाता है क्योंकि स्मृति आवंटित की जा सकती है और फिर मुक्त नहीं होती है।

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

मुझे अनुमान है कि यह .net कचरा कलेक्टर क्या करता है या परीक्षणों के बीच नहीं करता है। एक मामले में, कनेक्शन परीक्षण के बीच मुक्त कर रहे हैं; एक और मामले में, वे नहीं हैं।

मैं इसे कैसे समझा सकता हूं?

अद्यतन: आप में से उन लोगों के लिए कोड के विनिर्देशों के बारे में पूछना, यह आसान है। मैं अपनी सेटअप विधि में एक नया TransactionScope ऑब्जेक्ट घोषित करता हूं और इसे अपने Teardown विधि में निपटान करता हूं। हालांकि, समस्या परीक्षण 100 परीक्षण मामलों के साथ एक डेटा संचालित परीक्षण था; परीक्षण के तहत कोड ने SqlHelper वर्ग का उपयोग करके एक चयनित कथन से SqlDataReader ऑब्जेक्ट को पॉप्युलेट किया और फिर SqlDataReader पर बंद विधि को कॉल नहीं किया। क्योंकि मैंने एसक्लहैल्टर क्लास का उपयोग एसक्लडाटा रीडर प्राप्त करने के लिए किया था, इसलिए मुझे उम्मीद थी कि कनेक्शन मेरे लिए संभाले गए थे। ऐसा नहीं!

लेकिन को स्पष्ट करने के लिए, मैं अपनी विशिष्ट स्थिति के बारे में नहीं पूछ रहा हूं। मैं क्या जानना चाहता हूं: आम तौर पर, संसाधनों के बीच संसाधनों को कैसे मुक्त किया जाता है? मुझे लगता है कि यह कचरा कलेक्टर का कुछ आवेदन होगा। मुझे आश्चर्य है कि कचरा कलेक्टर अभी भी पिछले टेस्ट रन (रेस कंडीशन?)

अपडेट: यूनिट टेस्ट के साथ कचरा संग्रह के बारे में मुझे क्या पता है। अपनी जिज्ञासा के बाद, मैंने यूनिट परीक्षणों को खींच लिया जो असफल रहे क्योंकि SqlDataReader ऑब्जेक्ट द्वारा कनेक्शन खोला गया था। मैंने प्रत्येक परीक्षण के अंत में System.GC.Collect() जोड़ने का प्रयास किया। इसने कनेक्शन को सफलतापूर्वक मुक्त कर दिया, लेकिन ~ 50% प्रदर्शन जुर्माना लगाया।

+0

यदि आप कनेक्शन से बाहर हो रहे हैं क्योंकि आप परीक्षणों के बीच उनमें से पर्याप्त रिलीज नहीं करते हैं, तो मुझे संदेह होगा कि आपके आंसू के तरीकों में कोई समस्या है। उन्हें एक समय में चलाने पर, ओएस कुछ आंसू का ख्याल रखता है, लेकिन सूट के रूप में चलाता है आपका संसाधन उपयोग लंबे समय तक चलता रहता है। – MikeD

+1

हो सकता है कि आपको कहीं और कुछ 'निपटान' या 'बंद करें' कॉल कहीं और चाहिए? – Gabe

उत्तर

1

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

+0

वास्तव में?क्या आप मुझे कुछ दस्तावेज पर इंगित कर सकते हैं जो दिखाता है कि जीसी आमतौर पर अपने धागे पर चलती है? –

+1

http://stackoverflow.com/questions/318462/how-to-identify-the-gc-finalizer-thread –

+0

जीसी वास्तव में सभी धागे को संक्षेप में रोक सकता है, लेकिन यह लिंक में समझाया गया है, यह धागे में फाइनलर भी चलाता है। –

3

यह व्यवहार्य लगता है, हाँ। यूनिट टेस्ट फ्रेमवर्क के लिए यह आश्चर्यजनक नहीं होगा कि कचरा कलेक्टर परीक्षण के बीच चलता है।

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

मत भूलना यह शायद परीक्षण के बीच सभी कनेक्शन मुक्त करने के लिए नहीं था - उन्हें चालू रखने के लिए पर्याप्त ...

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

+0

जॉन, यदि आप इसे चूक गए, तो लुसेरो ने उल्लेख किया कि यह स्पष्ट रूप से पूरे ऐपडोमेन को उतार देता है, जिसे किसी भी रिसाव से छुटकारा पाना चाहिए। –

2

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

Cbrumme's blog on this topic भी देखें।

+0

आह, ठीक है। यदि यह ऐपडोमेन को उतारता है तो कचरा संग्रहण को बीच में मजबूर करने की आवश्यकता नहीं है। –

+0

बिल्कुल। चूंकि असेंबली को उतारने का एकमात्र तरीका उन्हें एक अलग एपडोमेन में रखना और एपडोमेन को उतारना है, इसलिए "संसाधन रिसाव क्लीनअप" इसका दुष्प्रभाव है। – Lucero

+0

अच्छा, चाहे वह दुष्प्रभाव है, आपके इरादे पर निर्भर करता है। मुझे लीड संसाधनों को साफ करने के लिए ऐपडोमेन्स का उपयोग करना पड़ा, असेंबली को साइड-इफेक्ट होने के उतारने के साथ। :-) –

1

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

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

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

0

वाह, यहां कई मुद्दे!

सबसे पहले, आप अपनी यूनिट परीक्षण श्रृंखला को तेज़ी से चाहते हैं। व्यापार तर्क का परीक्षण करने के लिए डेटाबेस को हिट न करें, आदि

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

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

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

using (SqlDataReader reader = ...) 
{ 
    ... 
} 
+0

आप 'उपयोग' के साथ 'SqlDataReader' का उपयोग कैसे कर सकते हैं। इसमें 'निपटान()' विधि नहीं है। –

+0

दोस्त यह आपके ऑब्जेक्ट ब्राउज़र को खोलता है और इसे चेक आउट करता है, इसे डिस्पोजेबल डीबीडेटा रीडर प्राप्त होता है - नीचे प्रकार की घोषणा देखें। बीटीडब्ल्यू, इनमें से अधिकतर डेटाबेस कनेक्शन से संबंधित प्रकारों को डिस्पोजेबल होना चाहिए क्योंकि वे विभिन्न ओएस संसाधनों को लपेटते हैं जिन्हें उपयोग किए जाने पर आवंटित किया जाता है। एक पाठक बंद करना प्रभावी रूप से इसे निपटाना है। उपयोग-बयानों का लाभ यह है कि अगर किसी अपवाद को फेंक दिया जाता है, तो भी इसका निपटान किया जाता है, असल में {foo.Dispose();} सार्वजनिक वर्ग SqlDataReader: DbDataReader, IDataReader, IDisposable, IDataRecord – Mahol25

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