JUnit

2013-07-18 6 views
12

से getResourceAsStream मैं एक परियोजना के लिए एक जुनीट टेस्टकेस बना रहा हूं जिसे प्रारंभिकरण के दौरान कॉन्फ़िगरेशन फ़ाइल लोड करने की आवश्यकता है।JUnit

यह कॉन्फ़िगरेशन फ़ाइल प्रोजेक्ट के अंदर src/main/resource/config फ़ोल्डर में है और बिल्ड मेवेन के दौरान इसे JAR के अंदर/config फ़ोल्डर में रखती है।

प्रारंभ वर्ग, वहाँ इस बयान का उपयोग करने से फ़ाइल में लिखा है:

ClassLoader classloader = this.getClass().getClassLoader(); 
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream("/config/config.xml"))); 

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

यह देखते हुए कि वर्ग my.package.MyClassTest.java है, और यह src/परीक्षण/जावा में रहती है कि/मेरी/पैकेज/MyClassTest.java, मैं पहले से ही में config.xml फ़ाइल की एक प्रतिलिपि रखने की कोशिश की सफलता के बिना निम्न फ़ोल्डरों:

- src/test/resources/config 
- src/test/resources/my/package/config 
- src/test/java/my/package/config 

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

तो, मुझे इस फ़ाइल को अपने जुनीट परीक्षण में उपयोग करने में सक्षम होने के लिए कहां रखना चाहिए?

अद्यतन

मैं सिर्फ कोड में एक छोटा सा परिवर्तन के साथ समाधान के साथ आया था: इसके बजाय classloader का उपयोग कर संसाधन प्राप्त करने के लिए की है, मैं सीधे वर्ग प्रयोग किया है:

Class clazz = this.getClass(); 
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(clazz.getResourceAsStream("/config/config.xml"))); 

और यह फ़ाइल को सफलतापूर्वक src/test/resource/config/config.xml से पढ़ता है। Class.getResourceAsStream विधि है::

हालांकि, वहाँ है यहाँ बहुत अजीब बात है

public InputStream getResourceAsStream(String name) { 
    name = resolveName(name); 
    ClassLoader cl = getClassLoader0(); 
    if (cl==null) { 
     // A system class. 
     return ClassLoader.getSystemResourceAsStream(name); 
    } 
    return cl.getResourceAsStream(name); 
} 

और अगर मैं यह डिबग, मैं स्पष्ट रूप से देख सकते हैं कि इस getClassLoader0() रिटर्न ठीक उसी वस्तु (उसी आईडी) पिछले कॉल की तुलना में, this.getClass()। getResourceAsStream() (जो मैंने बनाए रखा है, केवल मानों की तुलना करने के लिए) !!!

यहां क्या हो रहा है ?!

कार्य के बीच में एक नई विधि कॉल डालने के दौरान विधि को कॉल क्यों नहीं किया जाता है?

ईमानदारी से, मैं इसके सामने वास्तव में आश्चर्यचकित हूं।

बीटीडब्ल्यू, मैं जुनीट संस्करण 4.10 का उपयोग कर रहा हूं। क्या यह getClassLoader कॉल को किसी तरह से छेड़छाड़ कर सकता है?

बहुत धन्यवाद,

कार्ल्स

+1

ग्रहण में स्रोत/परीक्षण/संसाधन/स्रोत स्रोत है? –

+0

@SotiriosDelimanolis यदि आप इसे उत्तर के रूप में पोस्ट करते हैं, तो मैं इसे वोट दूंगा। –

+0

@ सॉटिरियोसेलिमैनोलिस: हाँ, यह है। दरअसल, जब मैंने इसे देखा तो मुझे एहसास हुआ कि ग्रहण इसे मैवेन परियोजनाओं के लिए डिफ़ॉल्ट रूप से लेता है। –

उत्तर

14

अपने प्रश्न का रूप में उत्तर दे

और अगर मैं यह डिबग, मैं स्पष्ट रूप से देख सकते हैं कि इस getClassLoader0() रिटर्न ठीक उसी वस्तु (एक ही आईडी) की तुलना में पिछले कॉल, this.getClass()। getResourceAsStream() (जो मैं बनाए रखा, बस मूल्यों की तुलना करने के लिए) !!!

यहां क्या हो रहा है ?!

कार्य के बीच में एक नई विधि कॉल डालने के दौरान विधि को कॉल क्यों नहीं किया जाता है?

this.getClass().getClassLoader().getResourceAsStream("/config/config.xml"); 

बुला और

this.getClass().getResourceAsStream("/config/config.xml"); 

बुला के बीच का अंतर सटीक स्रोत है कि आप Class से दिखा रहे थे में निहित है:

public InputStream getResourceAsStream(String name) { 
    name = resolveName(name); 
    ClassLoader cl = getClassLoader0(); 
    if (cl==null) { 
     // A system class. 
     return ClassLoader.getSystemResourceAsStream(name); 
    } 
    return cl.getResourceAsStream(name); 
} 

लेकिन समस्या यह नहीं हैके साथरिटर्न। यह दोनों मामलों में एक ही चीज़ देता है। अंतर वास्तव में resolveName(name) में है। यह Class कक्षा में एक निजी तरीका है।

private String resolveName(String name) { 
    if (name == null) { 
     return name; 
    } 
    if (!name.startsWith("/")) { 
     Class<?> c = this; 
     while (c.isArray()) { 
      c = c.getComponentType(); 
     } 
     String baseName = c.getName(); 
     int index = baseName.lastIndexOf('.'); 
     if (index != -1) { 
      name = baseName.substring(0, index).replace('.', '/') 
       +"/"+name; 
     } 
    } else { 
     name = name.substring(1); 
    } 
    return name; 
} 

तो आप वास्तव में classloader के getResourceAsStream() कॉल करने से पहले देखते हैं,, यह वास्तव में पथ से शुरू स्लैश निकाल देता है।

सामान्य तौर पर, यह जब यह एक स्लेश नहीं है this लिए संसाधन सापेक्ष प्राप्त करने की कोशिश, और classloader के लिए उस पर पारित अगर यह शुरुआत में एक स्लैश है जाएगा।

क्लासलोडर की getResourceAsStream() विधि वास्तव में सापेक्ष पथों के लिए उपयोग की जाने वाली है (अन्यथा आप केवल FileInputStream का उपयोग करेंगे)।

तो जब आप this.getClass().getClassLoader().getResourceAsStream("/config/config.xml"); इस्तेमाल किया है, तो आप वास्तव में यह पथ शुरुआत है, जो विफल रहा है में एक स्लैश के साथ गुजर रहे थे। जब आप this.getClass().getResourceAsStream("/config/config.xml"); इस्तेमाल किया यह एक तरह पर्याप्त था आप के लिए इसे हटाने के लिए।

+0

मुझे डर है कि मैं वर्तमान में इसका परीक्षण नहीं कर सकता (मैं मार्ग से पहले स्लैश मैन्युअल रूप से हटाने का प्रयास करना चाहता हूं और देख सकता हूं कि यह वही काम करता है), लेकिन यह समझदार लगता है। धन्यवाद, और स्वीकार किया। –

1

मैं इस बारे में निश्चित नहीं हूँ, लेकिन आप src/परीक्षण पेड़ के बजाय src/मुख्य पेड़ में अपने संसाधनों फ़ोल्डर डालने की कोशिश कर सकते। कुछ विन्यास में, कम से कम, src से कक्षाओं के लिए ग्रहण प्रतियां 'संसाधन' फ़ाइलों, लेकिन परीक्षण से नहीं वर्गों के लिए। यह एक शॉट के लायक है ...

+0

दोनों संसाधन फ़ोल्डर स्रोत/मुख्य और src/test में मौजूद हैं, जिसमें एक ही फाइल है ... लेकिन यह काम नहीं करता है। –

2

getResourceAsStreamClassLoader ऑब्जेक्ट से कार्य आपकी खोज स्ट्रिंग के साथ प्रीपेड स्लैश को नहीं हटाएगा क्योंकि सर्च क्लासपाथ के सापेक्ष किया जाएगा। iee संसाधन को खोजता है जहां खोज पथ कक्षाओं को लोड करने के लिए उपयोग किया जाता है।

उदाहरण के लिए कहो, तो अपनी कक्षा yourpackage/Test.class, जो /a/b/c/d/yourpackage/Test.class के नीचे स्थित है, प्रणाली classloader (अर्थात डिफ़ॉल्ट classloader) और अपने classpath द्वारा लोड क्रम वर्ग लोड करने के लिए /a/b/c/d को इंगित करना चाहिए।इस मार्ग पर खोज की जाएगी।

getResourceAsStream कक्षा ऑब्जेक्ट से फ़ंक्शन आपकी खोज स्ट्रिंग के साथ प्रीपेड स्लैश को हटा देता है क्योंकि खोज उस वर्ग के सापेक्ष किया जाएगा जहां यह रहता है। iee उस संसाधन की खोज करता है जहां आपकी कक्षा से लोड किया जा रहा है।

कहते हैं उदाहरण के लिए यदि yourpackage/Test.class/a/b/c/d/yourpackage/Test.class से भरी हुई तो संसाधन पथ हो जाएगा /a/b/c/d/yourpackage/config/config.xml

आप getResource और getResourceAsStream खोज के लिए एक ही एल्गोरिथ्म का पालन करने के लिए इस्तेमाल दोनों के बाद से इस निम्नलिखित कोड का उपयोग कर snipet परीक्षण कर सकते हैं।

System.out.println(Test.class.getClassLoader().getResource("config/config.xml")); 
System.out.println(Test.class.getResource("config/config.xml"));