मॉकिटो: विधि के भीतर बनाई गई किसी वस्तु पर विधि को कैसे सत्यापित किया जाए?


322

मैं मॉकिटो के लिए नया हूं।

नीचे दिए गए वर्ग को देखते हुए, मैं यह सत्यापित करने के लिए मॉकिटो का उपयोग कैसे कर सकता हूं कि someMethodएक बार लागू किए जाने के बाद fooइसे ठीक किया गया था?

public class Foo
{
    public void foo(){
        Bar bar = new Bar();
        bar.someMethod();
    }
}

मैं निम्नलिखित सत्यापन कॉल करना चाहूंगा,

verify(bar, times(1)).someMethod();

जहां barका एक नकली उदाहरण है Bar


2
stackoverflow.com/questions/6520242/… - लेकिन मैं PowerMock का उपयोग नहीं करना चाहता।
MRE

API या PowerMock बदलें। दोनों में से एक।
जॉन बी

कुछ इस तरह से कैसे कवर करें ?? सार्वजनिक सिंक्रनाइज़ किए गए शून्य प्रारंभ (बंडलकॉन्टेक्ट बंडललेकोटेक्स्ट) अपवाद फेंकता है {बंडलकंटेक्ट बीसी = बंडललेकोटेक्स्ट; logger.info ("स्टार्टिंग HTTP सर्विस बंडले"); this.tracker = new ServiceTracker (bc, HttpService.class.getName (), null) {@Override public Object addService (ServiceReference serviceRef) {httpService = (HttpService) super.addingService (serviceRef); registerServlets (); httpService लौटें; }}}
ShAkKiR

जवाबों:


365

निर्भरता अन्तःक्षेपण

यदि आप बार आवृत्ति, या एक कारखाने का उपयोग करते हैं जो बार आवृत्ति (या ऐसा करने के अन्य 483 तरीकों में से एक) बनाने के लिए उपयोग किया जाता है, तो आपके पास परीक्षण करने के लिए आवश्यक एक्सेस होगा।

फैक्टरी उदाहरण:

इस तरह लिखा गया एक फू वर्ग को देखते हुए:

public class Foo {
  private BarFactory barFactory;

  public Foo(BarFactory factory) {
    this.barFactory = factory;
  }

  public void foo() {
    Bar bar = this.barFactory.createBar();
    bar.someMethod();
  }
}

अपने परीक्षण विधि में आप इस तरह से एक BarFactory इंजेक्षन कर सकते हैं:

@Test
public void testDoFoo() {
  Bar bar = mock(Bar.class);
  BarFactory myFactory = new BarFactory() {
    public Bar createBar() { return bar;}
  };

  Foo foo = new Foo(myFactory);
  foo.foo();

  verify(bar, times(1)).someMethod();
}

बोनस: यह एक उदाहरण है कि TDD आपके कोड के डिज़ाइन को कैसे चला सकता है।


6
क्या इकाई परीक्षण के लिए कक्षा को संशोधित किए बिना ऐसा करने का कोई तरीका है?
MRE

6
Bar bar = mock(Bar.class)इसके बजायBar bar = new Bar();
जॉन बी

7
यह नही है कि मैं जानता हूँ। लेकिन, मैं सुझाव नहीं दे रहा हूं कि आप कक्षा को केवल इकाई परीक्षण के लिए संशोधित करें। यह वास्तव में स्वच्छ कोड और एसआरपी के बारे में बातचीत है। या .. क्या क्लास फू में बार ऑब्जेक्ट बनाने के लिए मेथड फू () की जिम्मेदारी है। यदि उत्तर हाँ है, तो यह एक कार्यान्वयन विवरण है और आपको विशेष रूप से इंटरैक्शन के परीक्षण के बारे में चिंता नहीं करनी चाहिए (@ माइकल के उत्तर को देखें)। यदि उत्तर नहीं है, तो आप कक्षा को संशोधित कर रहे हैं क्योंकि परीक्षण में आपकी कठिनाई एक लाल झंडा है जिसे आपके डिज़ाइन में थोड़ा सुधार करने की आवश्यकता है (इसलिए बोनस मैंने जोड़ा है कि कैसे TDD ड्राइव डिज़ाइन करता है)।
csturtz

3
क्या आप मॉकिटो के "सत्यापित" के लिए "वास्तविक" ऑब्जेक्ट पास कर सकते हैं?
जॉन बी

4
आप कारखाने का मजाक भी BarFactory myFactory = mock(BarFactory.class); when(myFactory.createBar()).thenReturn(bar);
उड़ा

18

क्लासिक प्रतिक्रिया है, "आप नहीं।" आप के सार्वजनिक एपीआई का परीक्षण करते हैं Foo, न कि इसके आंतरिक हिस्से का ।

क्या Fooवस्तु का कोई व्यवहार है (या, कम अच्छा, वातावरण में कोई अन्य वस्तु) जो इससे प्रभावित है foo()? यदि हां, तो वह परीक्षण करें। और यदि नहीं, तो विधि क्या करती है?


4
तो आप वास्तव में यहाँ क्या परीक्षण करेंगे? सार्वजनिक एपीआई Fooहै public void foo(), जहां इंटर्न केवल बार से संबंधित हैं।
बेहाल

15
केवल सार्वजनिक एपीआई का परीक्षण ठीक है, जब तक कि साइड-इफेक्ट्स के साथ वास्तविक बग न हों, जिन्हें परीक्षण की आवश्यकता होती है। उदाहरण के लिए, यह जाँचना कि एक निजी पद्धति अपने HTTP कनेक्शन को ठीक से बंद कर रही है, जब तक आपको पता नहीं चल जाता है कि निजी विधि अपने कनेक्शन को ठीक से बंद नहीं कर रही है, और इस तरह एक बड़ी समस्या पैदा हो रही है। उस बिंदु पर, मॉकिटो और verify()वास्तव में बहुत उपयोगी हो जाता है, भले ही आप एकीकरण परीक्षण के पवित्र वेदी पर पूजा नहीं कर रहे हों।
डॉनगरपोनी

@ डफ जे मैं जावा का उपयोग नहीं करता, लेकिन यह कुछ ऐसा लगता है जिसे आपके कंपाइलर या कोड विश्लेषण टूल को पता लगाना चाहिए।
user247702

3
मैं DuffJ से सहमत हूं, जबकि कार्यात्मक प्रोग्रामिंग मजेदार है, एक बिंदु आता है जहां आपका कोड बाहरी दुनिया के साथ बातचीत करता है। इससे कोई फर्क नहीं पड़ता कि आप इसे "इंटर्नल", "साइड इफेक्ट्स", या "कार्यक्षमता" कहते हैं, आप निश्चित रूप से उस इंटरैक्शन का परीक्षण करना चाहते हैं: यदि ऐसा होता है, और यदि यह सही संख्या में और सही तर्कों के साथ होता है। @Stijn: यह एक बुरा उदाहरण हो सकता है (लेकिन यदि कई कनेक्शन खोले जाने चाहिए, और उनमें से केवल कुछ बंद हो गए हैं, तो यह दिलचस्प है)। मौसम की जाँच करने के लिए एक बेहतर उदाहरण होगा कि कनेक्शन पर सही डेटा भेजा गया होगा।
एंड्रास बालाज़ लाजथा

13

यदि आप DI या कारखानों का उपयोग नहीं करना चाहते हैं। आप अपनी कक्षा को थोड़ा मुश्किल तरीके से रिफ्लेक्टर कर सकते हैं:

public class Foo {
    private Bar bar;

    public void foo(Bar bar){
        this.bar = (bar != null) ? bar : new Bar();
        bar.someMethod();
        this.bar = null;  // for simulating local scope
    }
}

और आपका परीक्षण वर्ग:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock Bar barMock;
    Foo foo;

    @Test
    public void testFoo() {
       foo = new Foo();
       foo.foo(barMock);
       verify(barMock, times(1)).someMethod();
    }
}

तब जो वर्ग आपके फू विधि को बुला रहा है, वह इसे इस तरह करेगा:

public class thirdClass {

   public void someOtherMethod() {
      Foo myFoo = new Foo();
      myFoo.foo(null);
   }
}

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

बेशक नकारात्मक पक्ष यह है कि आप कॉलर को बार ऑब्जेक्ट सेट करने की अनुमति दे रहे हैं।

आशा है ये मदद करेगा।


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

8

अपने उदाहरण कोड का उपयोग करने के लिए समाधान PowerMockito.whenNew

  • मॉकिटो-सभी 1.10.8
  • powermock-core 1.6.1
  • powermock-मॉड्यूल-जून 4 1.6
  • powermock-api-mockito 1.6.1
  • कनिष्ठ 4.12

FooTest.java

package foo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

//Both @PrepareForTest and @RunWith are needed for `whenNew` to work 
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Foo.class })
public class FooTest {

    // Class Under Test
    Foo cut;

    @Mock
    Bar barMock;

    @Before
    public void setUp() throws Exception {
        cut = new Foo();

    }

    @After
    public void tearDown() {
        cut = null;

    }

    @Test
    public void testFoo() throws Exception {

        // Setup
        PowerMockito.whenNew(Bar.class).withNoArguments()
                .thenReturn(this.barMock);

        // Test
        cut.foo();

        // Validations
        Mockito.verify(this.barMock, Mockito.times(1)).someMethod();

    }

}

JUnit आउटपुट JUnit आउटपुट


8

मुझे लगता है कि मॉकिटो @InjectMocksजाने का रास्ता है।

अपने इरादे के आधार पर आप उपयोग कर सकते हैं:

  1. कंस्ट्रक्टर इंजेक्शन
  2. प्रॉपर्टी सेटर इंजेक्शन
  3. फील्ड इंजेक्शन

डॉक्स में अधिक जानकारी

नीचे फ़ील्ड इंजेक्शन के साथ एक उदाहरण दिया गया है:

क्लास:

public class Foo
{
    private Bar bar = new Bar();

    public void foo() 
    {
        bar.someMethod();
    }
}

public class Bar
{
    public void someMethod()
    {
         //something
    }
}

परीक्षा:

@RunWith(MockitoJUnitRunner.class)
public class FooTest
{
    @Mock
    Bar bar;

    @InjectMocks
    Foo foo;

    @Test
    public void FooTest()
    {
        doNothing().when( bar ).someMethod();
        foo.foo();
        verify(bar, times(1)).someMethod();
    }
}

3

हां, यदि आप वास्तव में ऐसा करना चाहते हैं / करने की आवश्यकता है तो आप पावरमॉक का उपयोग कर सकते हैं। इसे अंतिम उपाय माना जाना चाहिए। पॉवरमॉक के साथ आप इसे कॉल से कंस्ट्रक्टर को मॉक वापस करने का कारण बन सकते हैं। फिर मॉक पर वेरिफिकेशन करें। उस ने कहा, csturtz का "सही" उत्तर है।

यहाँ नई वस्तुओं के मॉक निर्माण की कड़ी है


0

एक और सरल तरीका कुछ लॉग स्टेटमेंट को bar.someMethod () में जोड़ा जाएगा और फिर पता लगाया जाएगा कि आप उक्त संदेश को देख सकते हैं जब आपका परीक्षण निष्पादित किया जाता है, तो यहां उदाहरण देखें: लॉग ऑन में एक संदेश पर एक ज्यूनिट मुखर कैसे करें

यह विशेष रूप से तब उपयोगी है जब आपका Bar.someMethod () है private

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.