2012-11-27 12 views
6

द्वारा निष्पादित किया गया है, मैं क्लासपाथ में कुछ संसाधनों की क्वेरी के लिए Google Reflections library का उपयोग कर रहा हूं। वे संसाधन मेरी परियोजना में कक्षाओं की तुलना में एक ही स्थान पर स्थित हैं।प्रतिबिंब का उपयोग कर यूनिट परीक्षण Google लाइब्रेरी केवल तभी विफल होता है जब मैवेन

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

मैं उस निष्कर्ष पर पहुंचा कि कैसे प्रतिबिंब क्लासपाथ यूआरएल निर्धारित करता है जिसका निरीक्षण किया जाना चाहिए।

public static Set<URL> forClassLoader(ClassLoader... classLoaders) { 
    final Set<URL> result = Sets.newHashSet(); 
    for (ClassLoader classLoader : classLoaders) { 
     while (classLoader != null) { 
      if (classLoader instanceof URLClassLoader) { 
       URL[] urls = ((URLClassLoader) classLoader).getURLs(); 
       if (urls != null) { 
        result.addAll(Sets.<URL>newHashSet(urls)); 
       } 
      } 
      classLoader = classLoader.getParent(); 
     } 
    } 
    return result; 
} 

संक्षेप में, यह वर्ग लोडर पदानुक्रम के लिए पूछ traversing है: उदाहरण के लिए, निम्नलिखित विधि कैसे कुछ विचार एक वर्ग लोडर (मूल विचार विधि थोड़ा सरलीकृत किया गया है) दिया पाता उपलब्ध classpath यूआरएल पता चलता प्रत्येक व्यक्तिगत क्लासलोडर के यूआरएल।

ग्रहण में मैं कुछ इस तरह के साथ एक इकाई परीक्षण से पिछले विधि आह्वान जब:

ClassLoader myClassClassLoader = <MyClass>.class.getClassLoader(); //<MyClass> is in the same classpath url than the resources I need to find 
    Set<URL> urls = forClassLoader(myClassClassLoader); 
    for(URL url : urls) { 
     System.out.println("a url: " + url); 

की उम्मीद के रूप में, मैं (कई अन्य यूआरएल के अलावा) देख सकते हैं classpath URL हैं, जो के हिस्से के रूप में विन्यस्त कर रहे हैं मेरे परियोजना:

file:<MY_PROJECT_PATH>/target/classes/ 
file:<MY_PROJECT_PATH>/target/test-classes/ 

और कुछ विचार एक आकर्षण (संसाधनों विचार file:<MY_PROJECT_PATH>/target/classes/ में स्थित हैं खोजना चाहिए) के रूप में काम करता है।

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

"आश्चर्य की बात" बात यह है कि अगर मैं इस बारे में जब इकाई परीक्षण Maven द्वारा निष्पादित किया जाता है:

ClassLoader myClassClassLoader = <MyClass>.class.getClassLoader(); 
url = myClassClassLoader.getResource("anExistingResource"); 
System.out.println("URL: "+url); //a valid URL 

मैं देख सकता हूँ कि वर्ग लोडर अभी भी संसाधन मैं खोजने की कोशिश कर रहा हूँ हल कर सकते हैं। मैं इस बारे में परेशान हूं कि क्यों मेवेन के साथ निष्पादित किया गया था forClassLoader विधि में मेरे प्रोजेक्ट के क्लासपाथ यूआरएल लौटाए गए सेट में शामिल नहीं है, हालांकि साथ ही यह ऐसे यूआरएल (!) में स्थित संसाधनों को हल करने में सक्षम है।

इस व्यवहार का कारण क्या है? क्या मेवेन द्वारा चलाए गए यूनिट टेस्ट के हिस्से के रूप में आमंत्रित किए जाने पर मैं प्रतिबिंब लाइब्रेरी का काम करने की कोशिश कर सकता हूं?

+0

यूआरएल हैशसेट में है? मुझे इस जावा पहेली की याद दिलाई जा रही है: http://javaantipatterns.wordpress.com/2007/11/24/comparing-urls-with-urlequals/ – Rekin

+0

दिलचस्प लिंक @ रेकिन, लेकिन किसी भी मामले में उनको रखना संभव है समस्या के बिना एक सेट में यूआरएल, शायद क्योंकि वे स्थानीय जार और निर्देशिका (?) को इंगित कर रहे हैं यकीन नहीं है ... (मैंने वह कोड नहीं लिखा है, इसे सिर्फ प्रतिबिंब Google लाइब्रेरी से लिया है)। जिज्ञासा से बाहर, अगर आपको पता है कि यह क्यों काम कर रहा है (स्पष्ट रूप से आपके लिंक का विरोधाभास) कृपया मुझे बताएं! – Sergio

उत्तर

3

आप शायद एम 2 एक्लिप्स का उपयोग कर रहे हैं, जो क्लासपाथ में सामान जोड़ता है। कमांड लाइन मेवेन अलग-अलग काम करता है। आपको some options that will help मिल सकता है।

+0

ऐसा लगता है कि निश्चित प्लगइन निश्चित रूप से आग नहीं लगा। –

+0

ने एक ही परिणाम के साथ कमांड लाइन मेवेन के साथ कोशिश की है – Sergio

+0

+1 @ user237815 लिंक के लिए धन्यवाद। मुझे लगता है कि मैं प्रभावी क्लासपाथ खोजने का अपना समाधान पसंद करता हूं, क्योंकि इस तरह से मेरी लाइब्रेरी मेनिफेस्ट फाइलों में घोषित कक्षाओं के साथ काम करेगी (मुझे पता चला कि यह उन परिस्थितियों में काम नहीं कर रहा था "मेवेन के साथ इस समस्या के लिए धन्यवाद", लेकिन मैं मैं आपके जवाब को खुशी से स्वीकार कर रहा हूं क्योंकि मुझे लिंक में उल्लिखित विकल्पों को नहीं पता था! – Sergio

0

कुछ ऐसे मुद्दे हैं जिन्हें आप बना सकते हैं जो सुनिश्चित करता है कि असफल असफल हो।

  1. नामकरण सम्मेलन है; परीक्षण सूट को 'टेस्टबालाबाला' या 'ब्लैब्लाटेस्ट' कहा जाना चाहिए; शब्द 'टेस्ट' से शुरू या समाप्त होता है।

  2. जैसा कि पहले उल्लेख किया गया है, मेवेन में क्लासपाथ ग्रहण में है जितना ग्रहण में है (बेवकूफ) टेस्ट क्लासपाथ से संकलित वर्गपथ को अलग नहीं करता है।

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

3 डीबग करने के लिए सबसे कठिन है जो मैं आपको बता सकता हूं; जब भी ग्रहण में कुछ काम करता है और मैवेन में नहीं, तो मैं स्वाभाविक रूप से मानता हूं कि मैं परीक्षण सूट को अलग करने में कुछ गलत कर रहा हूं।

+0

हाय @ गिम्बी। मैं नामकरण सम्मेलनों का पालन कर रहा हूं और मेरे सरल परीक्षणों में कोई दौड़ की स्थिति नहीं है, इसलिए इससे कोई फर्क नहीं पड़ता कि उन्हें किसी भी क्रम में निष्पादित किया गया है या नहीं। मुझे लगता है कि यह मेवेन में क्लास लोडिंग से संबंधित कुछ है लेकिन फिर भी मुझे यह नहीं पता कि समस्या वास्तव में क्या है। – Sergio

4

इसे हल किया गया। अगर किसी को भविष्य में कोई समस्या मिलती है तो समाधान पोस्ट करना।

किसी प्रोजेक्ट के यूनिट परीक्षणों को निष्पादित करते समय, मैवेन क्लासपाथ में अपनी स्पष्टताओं को स्पष्ट रूप से शामिल नहीं करता है। इसके बजाय, यह "लक्ष्य/surefire/surefirebooter_NUMBER_THAT_LOOKS_LIKE_TIME_STAMP.jar" में स्थित एक tmp jar पर निर्भरता घोषित करता है। इस जार में केवल एक मेनिफेस्ट फ़ाइल है जो प्रोजेक्ट के लिए क्लासपाथ घोषित करती है।

विचार पुस्तकालय प्रभावी classpath साथ यूआरएल का एक सेट वापस नहीं करता है में विधि forClassLoader (अर्थात, प्रकट फाइलों में classpath प्रविष्टियों पर ध्यान नहीं जाता है)। इस पर काबू पाने के लिए, मैं सिर्फ इस सरल विधि लागू:

public static Set<URL> effectiveClassPathUrls(ClassLoader... classLoaders) { 
    return ClasspathHelper.forManifest(ClasspathHelper.forClassLoader(classLoaders)); 
} 

विधि forManifest (भी कुछ विचार पुस्तकालय का हिस्सा) पैरामीटर के रूप में भेजा classpath यूआरएल के सेट करने के लिए कहते हैं, लापता classpath प्रविष्टियों में से प्रकट फाइलों में घोषित सेट में निहित कोई जार फाइलें। इस तरह से विधि परियोजना के प्रभावी वर्गपथ के साथ यूआरएल का एक सेट देता है।

+3

ठीक है, या आप मेरे समाधान का प्रयास कर सकते हैं। लिंक को देखो। UseManifestOnlyJar = झूठी जोड़ने का प्रयास करें और surefireLoader = surefire प्लगइन में सही उपयोग करें। – ccleve

+0

@ccleve, ऐसा लगता है कि इससे मदद मिली है। धन्यवाद! –

2

मुझे एक ही समस्या थी। निम्नलिखित यूआरएल जोड़ना मेरे लिए चाल है।

ConfigurationBuilder cb = new ConfigurationBuilder(); 
cb.setUrls(...); 
cb.addUrls(YourClassName.class.getProtectionDomain().getCodeSource().getLocation()); 
+0

यह मेरे लिए भी काम किया। मेरे पास उत्पादन कोड में एक URLClassLoader है जो कुछ JAR लोड करता है, इसलिए मैं यूआरएल का ट्रैक रखता हूं और प्रतिबिंब के लिए उनका उपयोग करता हूं, और परीक्षणों के लिए मैं सिर्फ उस विधि का नकल करता हूं जो यूआरएल को पुनर्प्राप्त करता है और जो आपको मिला है उसे वापस लौटाता है। जिस एप्लिकेशन पर मैं काम कर रहा हूं उसका क्लासपाथ बिल्कुल विशाल है, और स्पष्ट रूप से स्कैन समय को स्कैन करने के लिए URL को 5 सेकंड से 80 मिलीसेकंड तक स्कैन करने के लिए निर्दिष्ट करता है। –

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