java - जूनिट और जावा: गैर-सार्वजनिक तरीकों का परीक्षण




unit-testing testing (12)

जुनीट केवल मेरी कक्षा में उन विधियों का परीक्षण करेगा जो सार्वजनिक हैं। मैं उन लोगों पर जूनिट परीक्षण कैसे करूं जो (यानि, निजी, संरक्षित) नहीं हैं?

मैं जूनिट का उपयोग न करके उनका परीक्षण कर सकता हूं, लेकिन मैं सोच रहा था कि जूनिट मानक विधि क्या थी।


डीपी 4 जे जार

निजी तरीकों का परीक्षण करने के लिए हमें प्रतिबिंब का उपयोग करने और सभी उत्तरों में इसकी ओर इशारा करने की आवश्यकता है।

अब यह कार्य Dp4j जार की मदद से सरलीकृत है।

  • डीपी 4 जे आपके कोड का विश्लेषण करता है और आपके लिए प्रतिबिंब एपीआई कोड स्वचालित रूप से उत्पन्न करता है।

  • बस अपने क्लासस्पैट में dp4j.jar जोड़ें।

  • Dp4j.jar में एनोटेशन प्रोसेसर शामिल हैं, वे आपके कोड में विधियों की तलाश करेंगे जो @Test JUnit एनोटेशन के साथ एनोटेटेड हैं।

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

here अधिक जानकारी प्राप्त here


"PrivateAccessor.invoke" की तलाश करें। मेरा कोड इसे "junitx.util" से आयात करता है, लेकिन मुझे नहीं पता कि यह कहां से आया था।


आप जुनीट के बजाय टेस्टएनजी का उपयोग कर सकते हैं, जो कि निजी या सार्वजनिक विधि की परवाह नहीं करता है।


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


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

यदि यह काम नहीं करता है, तो जुनीटएक्स निजी तरीकों का परीक्षण करने की अनुमति देता है, हालांकि मुझे लगता है कि यह केवल जुनीट 3.8 के लिए उपलब्ध है।


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

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

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

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


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


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

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

मेरे अनुभव में, यूनिट परीक्षण निजी तरीकों की आवश्यकता होने के कारण एक संकेतक है कि आप जो टेस्ट कर रहे हैं वह सरल हो सकता है (और चाहिए)।

यही है, अगर आप अभी भी वास्तव में जरूरत महसूस करते हैं:

  • संरक्षित तरीकों का परीक्षण सबक्लास द्वारा किया जा सकता है;
  • यूनिट परीक्षणों को उसी पैकेज में डालकर पैकेज निजी तरीकों का परीक्षण किया जा सकता है; तथा
  • निजी तरीकों को यूनिट द्वारा परीक्षण किया जा सकता है, उदाहरण के लिए, पैकेज निजी फैक्ट्री प्रॉक्सी विधि। आदर्श नहीं है लेकिन निजी का मतलब निजी है।

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

मान लीजिए कि आपके पास ऐसी कार्यक्षमता है जिसे आप कक्षा में आंतरिक रूप से अलग करना चाहते हैं। उदाहरण के लिए, मान लीजिए मेरे पास ऐसा कुछ है:

public class HolderOfSomeStrings{

    private List<String> internal_values;

    public List<String> get()
    {
       List<String> out = new ArrayList<String>();
       for (String s:internal_values)
       { 
           out.add(process(s));
       }
      return get;
    }

   private static String process(String input)
   {
     //do something complicated here that other classes shouldn't be interested in
    }

}

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


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

public void testPrivateField() throws InterruptedException {
    Class<ClassWPrivateField> clazz = ClassWPrivateField.class;
    try {
        Field privateField = clazz.getDeclaredField("nameOfPrivateField");
        privateField.setAccessible(true); // This is the line
        // do stuff
    } catch(NoSuchFieldException nsfe) {
        nsfe.printStackTrace();
        fail();
    } catch(IllegalAccessException iae) {
        iae.printStackTrace();
        fail();
    }

}

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

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

निजी तरीकों को कॉल करना encapsulation को नष्ट कर सकता है और वास्तव में परीक्षण को अमान्य कर सकता है।


सबसे आसान समाधान JUnit परीक्षण को उसी पैकेज (लेकिन अलग निर्देशिका) में रखना है और विधियों के लिए डिफ़ॉल्ट (यानी पैकेज-निजी) दृश्यता का उपयोग करना है।

एक और अधिक जटिल दृष्टिकोण निजी तरीकों तक पहुंचने के लिए प्रतिबिंब का उपयोग करना है।






junit