मॉकिटो का उपयोग करके निजी विधि का परीक्षण


104
सार्वजनिक वर्ग ए {

    सार्वजनिक शून्य विधि (बूलियन बी) {
          अगर (b == सच)
               Method1 ();
          अन्य
               Method2 ();
    }

    निजी शून्य विधि 1 () {}
    निजी शून्य विधि 2 () {}
}
पब्लिक क्लास टेस्टा {

    @परीक्षा
    सार्वजनिक शून्य परीक्षणमेथोड () {
      ए = मॉक (एक्लास);
      a.method (सही);
      // कैसे सत्यापित करें (a) .method1 () की तरह परीक्षण करें;
    }
}

निजी विधि का परीक्षण कैसे किया जाता है या नहीं, और मॉकिटो का उपयोग करके निजी विधि का परीक्षण कैसे किया जाता है ???


जवाबों:


81

आप मॉकिटो के साथ ऐसा नहीं कर सकते हैं लेकिन मॉकिटो का विस्तार करने के लिए आप पावरमॉक का उपयोग कर सकते हैं और निजी तरीकों का उपयोग कर सकते हैं । पॉवर्मॉक मॉकिटो का समर्थन करता है। यहाँ एक उदाहरण है।


19
मैं इस जवाब से उलझन में हूं। यह मजाक है, लेकिन शीर्षक निजी विधियों का परीक्षण कर रहा है
diyoda_

मैंने पावरमॉक का उपयोग निजी पद्धति का मजाक उड़ाने के लिए किया है, लेकिन मैं पावरमॉक के साथ निजी पद्धति का परीक्षण कैसे कर सकता हूं। जहां, मैं कुछ इनपुट पास कर सकता हूं और विधि से कुछ आउटपुट की उम्मीद कर सकता हूं और फिर आउटपुट को सत्यापित कर सकता हूं?
रिटो

आप इनपुट आउटपुट का मजाक नहीं उड़ा सकते, आप वास्तविक कार्यक्षमता का परीक्षण नहीं कर सकते।
तल्हा

131

मॉकिटो के माध्यम से संभव नहीं। उनकी विकि से

क्यों मॉकिटो निजी तरीकों का मजाक नहीं उड़ाता है?

सबसे पहले, हम निजी तरीकों का मजाक उड़ाने के बारे में हठधर्मी नहीं हैं। हम सिर्फ निजी तरीकों की परवाह नहीं करते हैं क्योंकि निजी तरीकों के परीक्षण के दृष्टिकोण मौजूद नहीं हैं। यहां कुछ कारण दिए गए हैं कि मॉकिटो निजी तरीकों का मजाक नहीं उड़ाता है:

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

आसपास काम करना बहुत आसान है - बस निजी से पैकेज-संरक्षित (या संरक्षित) की विधि की दृश्यता को बदल दें।

इसे लागू करने और इसे बनाए रखने के लिए मुझे समय बिताना होगा। और यह दिए गए बिंदु # 2 और इस तथ्य से कोई मतलब नहीं है कि यह पहले से ही अलग-अलग टूल (पावरमॉक) में लागू है।

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


1
उस कथन के द्वारा एक घातक धारणा बनाई गई है:> निजी तरीकों का मजाक उड़ाना एक संकेत है कि OO की समझ में कुछ गड़बड़ है। यदि मैं एक सार्वजनिक विधि का परीक्षण कर रहा हूं, और यह निजी तरीकों को बुलाती है, तो मैं निजी विधि रिटर्न का मजाक बनाना चाहूंगा। उपरोक्त धारणा के अनुसार जाने से निजी तरीकों को लागू करने की आवश्यकता भी कम हो जाती है । ओओ की खराब समझ कैसी है?
अंडामट्टर्स

1
@eggmatters बाल्डुंग के अनुसार "मॉकिंग तकनीक को वर्ग की बाहरी निर्भरता पर लागू किया जाना चाहिए न कि कक्षा के लिए। यदि हमारी कक्षाओं के परीक्षण के लिए निजी तरीकों का मजाक उड़ाना आवश्यक है, तो यह आमतौर पर एक खराब डिजाइन को इंगित करता है।" यहाँ इसके बारे में एक अच्छा सूत्र दिया गया है। softwareengineering.stackexchange.com/questions/100959/…
जेसन ग्लीज़

34

यहाँ एक छोटा सा उदाहरण है कि कैसे साथ यह करने के लिए है powermock

public class Hello {
    private Hello obj;
    private Integer method1(Long id) {
        return id + 10;
    }
} 

Method1 का उपयोग करने के लिए कोड का उपयोग करें:

Hello testObj = new Hello();
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));

निजी वस्तु सेट करने के लिए obj इस का उपयोग करें:

Hello testObj = new Hello();
Hello newObject = new Hello();
Whitebox.setInternalState(testObj, "obj", newObject);

आपका लिंक केवल पावर मॉक रेपो @Mindaugas
Xavier

@ ज़ेवियर सच। आप इसे अपने प्रोजेक्ट में पसंद कर सकते हैं।
मिन्दुगास जारमिनस

1
आश्चर्यजनक !!! इतनी अच्छी तरह से इन सरल उदाहरण के साथ लगभग सब कुछ समझाया :) क्योंकि उद्देश्य सिर्फ कोड का परीक्षण करना है और न कि सभी रूपरेखा क्या प्रदान करता है :)
सिद्धार्थ

कृपया इसे अपडेट करें। व्हाइटबॉक्स अब सार्वजनिक एपीआई का हिस्सा नहीं है।
user447607

17

व्यवहार के संदर्भ में इस बारे में सोचें, न कि वे कौन से तरीके हैं। कहा जाता है methodकि विधि एक विशेष व्यवहार है अगर bसच है। bझूठा होने पर इसका व्यवहार अलग होता है। इसका मतलब है कि आपको दो अलग-अलग परीक्षण लिखने चाहिए method; प्रत्येक मामले के लिए एक। इसलिए तीन विधि-उन्मुख परीक्षण (एक के लिए method, एक के लिए method1, एक के लिए method2) के बजाय, आपके पास दो व्यवहार-उन्मुख परीक्षण हैं।

इससे संबंधित (मैंने हाल ही में एक और SO थ्रेड में यह सुझाव दिया था, और परिणामस्वरूप चार-अक्षर वाला शब्द मिला, इसलिए इसे नमक के एक दाने के साथ लेने के लिए स्वतंत्र महसूस करें); मुझे परीक्षण के नाम चुनने में मदद मिलती है जो उस व्यवहार को दर्शाते हैं जो मैं विधि के नाम के बजाय परीक्षण कर रहा हूं। इसलिए अपने परीक्षणों को न बुलाएंtestMethod() , testMethod1(), testMethod2()और इसके आगे। मुझे ऐसे नाम पसंद हैं calculatedPriceIsBasePricePlusTax()या taxIsExcludedWhenExcludeIsTrue()जो इंगित करते हैं कि मैं किस व्यवहार का परीक्षण कर रहा हूं; फिर प्रत्येक परीक्षण विधि के भीतर, केवल संकेतित व्यवहार का परीक्षण करें। इस तरह के अधिकांश व्यवहारों में सार्वजनिक पद्धति के लिए केवल एक कॉल शामिल होगी, लेकिन इसमें निजी कॉल के लिए कई कॉल शामिल हो सकते हैं।

उम्मीद है की यह मदद करेगा।


13

जबकि मॉकिटो उस क्षमता को प्रदान नहीं करता है, आप मॉकिटो + ज्यूनिट रिफ्लेक्शन यूटिल्स क्लास या स्प्रिंग रिफ्लेक्शनटाइस्टिल्स क्लास का उपयोग करके समान परिणाम प्राप्त कर सकते हैं । कृपया से लिया निम्न उदाहरण देख यहाँ समझा एक निजी विधि आह्वान करने के लिए कैसे:

ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");

ReflectionTestUtils और Mockito के साथ पूरा उदाहरण स्प्रिंग के लिए Mockito पुस्तक में पाया जा सकता है


ReflectionTestUtils.invokeMethod (छात्र, "saveOrUpdate", "तर्क 1", "तर्क 2", "तर्क 3"); InvokeMethod का अंतिम तर्क, Vargs का उपयोग करता है जो निजी तर्क को पारित करने के लिए कई तर्क ले सकता है। यह काम करता हैं।
टिम

इस उत्तर में अधिक तरीके होने चाहिए, निजी तरीकों का परीक्षण करने का सबसे आसान तरीका।
मैक्स

9

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

क्या मैं उचित निर्भरता इंजेक्शन का उपयोग कर रहा हूँ? क्या मुझे संभवतः निजी तरीकों को एक अलग वर्ग में ले जाने की आवश्यकता है और यह परीक्षण करना चाहिए? क्या ये तरीके निजी होने चाहिए? ... क्या वे डिफ़ॉल्ट या संरक्षित नहीं हो सकते?

उपर्युक्त उदाहरण में, दो विधियों को जिन्हें "बेतरतीब ढंग से" कहा जाता है, वास्तव में अपने स्वयं के वर्ग में रखा जा सकता है, परीक्षण किया जाता है और फिर ऊपर की कक्षा में अंतःक्षिप्त किया जाता है।


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

2
प्रसिद्ध सुपरटनस्की, मैं सामान्य मामले की बात कर रहा था। मैं सहमत हूं कि उपरोक्त मामले में यह एक अलग वर्ग में नहीं होना चाहिए। (हालांकि आपकी टिप्पणी पर +1 - यह एक बहुत ही मान्य बिंदु है जिसे आप निजी सदस्यों को बढ़ावा देने के लिए बना रहे हैं)
जैको वान नीकर

4
@supertonsky, मैं इस समस्या पर कोई संतोषजनक प्रतिक्रिया नहीं पा रहा हूँ। कई कारण हैं कि मैं निजी सदस्यों का उपयोग क्यों कर सकता हूं और बहुत बार वे एक कोड गंध का संकेत नहीं देते हैं और मुझे उनके परीक्षण से बहुत लाभ होगा। लोग इसे "बस मत करो" कहकर ब्रश करना शुरू कर देते हैं।
लुडिपेंट्स

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

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

6

मैं प्रतिबिंब का उपयोग करके मॉकिटो का उपयोग करके एक निजी विधि का परीक्षण करने में सक्षम था। यहाँ उदाहरण है, इसे ऐसे नाम देने की कोशिश की जाती है कि यह समझ में आता है

//Service containing the mock method is injected with mockObjects

@InjectMocks
private ServiceContainingPrivateMethod serviceContainingPrivateMethod;

//Using reflection to change accessibility of the private method

Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
    Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
    //making private method accessible
    m.setAccessible(true); 
    assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));

6
  1. प्रतिबिंब का उपयोग करके, परीक्षण विधियों से निजी तरीकों को बुलाया जा सकता है। इस मामले में,

    // परीक्षा विधि इस तरह होगी ...

    public class TestA {
    
      @Test
        public void testMethod() {
    
        A a= new A();
        Method privateMethod = A.class.getDeclaredMethod("method1", null);
        privateMethod.setAccessible(true);
        // invoke the private method for test
        privateMethod.invoke(A, null);
    
        }
    }
  2. यदि निजी विधि किसी अन्य निजी विधि को कॉल करती है, तो हमें वस्तु की जासूसी करने की जरूरत है और एक अन्य विधि को जमा करना होगा। टेस्ट क्लास की तरह होगा ...

    // परीक्षा विधि इस तरह होगी ...

    public class TestA {
    
      @Test
        public void testMethod() {
    
        A a= new A();
        A spyA = spy(a);
        Method privateMethod = A.class.getDeclaredMethod("method1", null);
        privateMethod.setAccessible(true);
        doReturn("Test").when(spyA, "method2"); // if private method2 is returning string data
        // invoke the private method for test
        privateMethod.invoke(spyA , null);
    
        }
    }

** दृष्टिकोण प्रतिबिंब को संयोजित करना और वस्तु की जासूसी करना है। ** method1 और ** method2 निजी तरीके हैं और method1 कॉल मेथड 2 हैं।


4

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

कुछ संभावित समाधान (AFAIK):

  1. अपने निजी तरीकों का मज़ाक उड़ाते हुए, लेकिन फिर भी आप अपने तरीकों का परीक्षण "वास्तव में" नहीं करेंगे।

  2. विधि में प्रयुक्त वस्तु की स्थिति का सत्यापन करें। MOSTLY विधियाँ या तो इनपुट मानों की कुछ प्रसंस्करण करती हैं और एक आउटपुट लौटाती हैं, या वस्तुओं की स्थिति को बदल देती हैं। वांछित राज्य के लिए वस्तुओं का परीक्षण भी नियोजित किया जा सकता है।

    public class A{
    
    SomeClass classObj = null;
    
    public void publicMethod(){
       privateMethod();
    }
    
    private void privateMethod(){
         classObj = new SomeClass();
    }
    
    }

    [यहां आप निजी पद्धति के लिए परीक्षण कर सकते हैं, क्लासऑब्ज के राज्य परिवर्तन को शून्य से शून्य तक की जांच करके।]

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

    कोड।

    public class A
    { 
        public int method(boolean b)
        {
              int nReturn = 0;
              if (b == true)
                   nReturn = method1();
              else
                   nReturn = method2();
        }
    
        private int method1() {}
    
        private int method2() {}
    
    }

3

वास्तव में मॉकिटो के साथ एक निजी सदस्य के तरीकों का परीक्षण करने का एक तरीका है। मान लीजिए कि आपके पास एक वर्ग है:

public class A {
    private SomeOtherClass someOtherClass;
    A() {
        someOtherClass = new SomeOtherClass();
    }
    public void method(boolean b){
        if (b == true)
            someOtherClass.method1();
        else
            someOtherClass.method2();
    }

}

public class SomeOtherClass {
    public void method1() {}
    public void method2() {}
}

यदि आप परीक्षण करना चाहते हैं तो a.methodएक विधि से आह्वान करेंगे SomeOtherClass, आप नीचे कुछ लिख सकते हैं।

@Test
public void testPrivateMemberMethodCalled() {
    A a = new A();
    SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
    ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
    a.method( true );

    Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
}

ReflectionTestUtils.setField(); निजी सदस्य को किसी ऐसी चीज़ से रूबरू कराएँगे जिसकी आप जासूसी कर सकते हैं।


2

अपना परीक्षण एक ही पैकेज में रखें, लेकिन एक अलग स्रोत फ़ोल्डर (src / main / java बनाम src / test / java) और उन तरीकों को पैकेज-निजी बनाएं। Imo testability गोपनीयता से अधिक महत्वपूर्ण है।


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

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

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

0

ऐसे मामलों में जहां निजी विधि शून्य नहीं है और रिटर्न मान का उपयोग बाहरी निर्भरता की विधि के पैरामीटर के रूप में किया जाता है, आप निर्भरता का मजाक उड़ा सकते हैं और ArgumentCaptorरिटर्न मान पर कब्जा करने के लिए उपयोग कर सकते हैं । उदाहरण के लिए:

ArgumentCaptor<ByteArrayOutputStream> csvOutputCaptor = ArgumentCaptor.forClass(ByteArrayOutputStream.class);
//Do your thing..
verify(this.awsService).uploadFile(csvOutputCaptor.capture());
....
assertEquals(csvOutputCaptor.getValue().toString(), "blabla");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.