मॉकिटो का उपयोग करते समय मॉकिंग और जासूसी के बीच अंतर क्या है?


137

एक मॉकिटो जासूस के उपयोग के लिए एक उपयोग मामला क्या होगा?

यह मुझे लगता है कि हर जासूस उपयोग के मामले को मॉक के साथ हैंडल किया जा सकता है, कॉलरीथेलेथोड का उपयोग करके।

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

जवाबों:


100

उत्तर दस्तावेज में है :

वास्तविक आंशिक नकली (1.8.0 के बाद से)

अंत में, मेलिंग सूची पर कई आंतरिक बहस और चर्चाओं के बाद, मॉकिटो में आंशिक नकली समर्थन जोड़ा गया। पहले हम आंशिक नकली को कोड की गंध मानते थे। हालांकि, हमें आंशिक मोक्स के लिए वैध उपयोग का मामला मिला।

रिलीज से पहले 1.8 स्पाई () वास्तविक आंशिक मोक्स का उत्पादन नहीं कर रहा था और यह कुछ उपयोगकर्ताओं के लिए भ्रमित था। जासूसी के बारे में अधिक पढ़ें: यहां या जावदोक में जासूसी (वस्तु) विधि के लिए।

callRealMethod()के बाद शुरू किया गया था spy(), लेकिन जासूसी () को निश्चित रूप से पीछे छोड़ दिया गया था, ताकि पिछड़े संगतता को सुनिश्चित किया जा सके।

अन्यथा, आप सही हैं: जासूसी के सभी तरीके असली हैं जब तक कि ठूंठ नहीं हैं। मॉक के सभी तरीकों को जब तक नहीं callRealMethod()कहा जाता है, तब तक ठूंसा जाता है। सामान्य तौर पर, मैं उपयोग करना पसंद करूंगा callRealMethod(), क्योंकि यह मुझे doXxx().when()पारंपरिक के बजाय मुहावरे का उपयोग करने के लिए मजबूर नहीं करता हैwhen().thenXxx()


इन मामलों में जासूसी को अधिक पसंद करने के साथ समस्या यह है कि जब वर्ग एक सदस्य का उपयोग करता है जिसे इसमें इंजेक्ट नहीं किया जाता है (लेकिन स्थानीय रूप से प्रारंभिक), और बाद में "वास्तविक" विधि द्वारा उपयोग किया जाता है; मजाक में, सदस्य को उसके डिफ़ॉल्ट जावा मूल्य के लिए आरंभीकृत किया जाएगा, जिससे गलत व्यवहार या यहां तक ​​कि NullPointerException भी हो सकती है। इसे पास करने का तरीका एक "इनिट" विधि जोड़ना है और फिर "वास्तव में" इसे कॉल करना है, लेकिन यह मुझे थोड़ा अधिक लगता है।
ईयाल रोथ

डॉक्टर से: "जासूसों को सावधानी से और कभी-कभी इस्तेमाल किया जाना चाहिए, उदाहरण के लिए जब विरासत कोड के साथ काम कर रहे हों।" यूनिट टेस्टिंग स्पेस एक ही काम करने के कई तरीकों से ग्रस्त है।
५३ पर gdbj

89

एक जासूस और एक नकली के बीच अंतर

जब मॉकिटो एक नकली बनाता है - यह एक प्रकार के वर्ग से ऐसा करता है, वास्तविक उदाहरण से नहीं। मॉक बस क्लास की एक नंगे-हड्डियों के खोल का उदाहरण बनाता है, पूरी तरह से इसके साथ बातचीत को ट्रैक करने के लिए। दूसरी ओर, जासूस मौजूदा उदाहरण को लपेटेगा। यह अभी भी सामान्य उदाहरण की तरह ही व्यवहार करेगा - अंतर केवल इतना है कि इसके साथ सभी इंटरैक्शन को ट्रैक करने के लिए भी इसे इंस्ट्रूमेंट किया जाएगा।

निम्नलिखित उदाहरण में - हम ArrayList वर्ग का मजाक बनाते हैं:

@Test
public void whenCreateMock_thenCreated() {
    List mockedList = Mockito.mock(ArrayList.class);

    mockedList.add("one");
    Mockito.verify(mockedList).add("one");

    assertEquals(0, mockedList.size());
}

जैसा कि आप देख सकते हैं - एक तत्व को नकली सूची में जोड़ना वास्तव में कुछ भी नहीं जोड़ता है - यह विधि को बिना किसी अन्य दुष्प्रभाव के कहता है। दूसरी ओर एक जासूस अलग तरह से व्यवहार करेगा - यह वास्तव में ऐड पद्धति के वास्तविक कार्यान्वयन को बुलाएगा और तत्व को अंतर्निहित सूची में जोड़ देगा:

@Test
public void whenCreateSpy_thenCreate() {
    List spyList = Mockito.spy(new ArrayList());
    spyList.add("one");
    Mockito.verify(spyList).add("one");

    assertEquals(1, spyList.size());
}

यहाँ हम यह निश्चित रूप से कह सकते हैं कि ऑब्जेक्ट की वास्तविक आंतरिक विधि को इसलिए कहा गया क्योंकि जब आप आकार () विधि को 1 के रूप में आकार प्राप्त करते हैं, लेकिन इस आकार () विधि का मजाक नहीं उड़ाया जाता है! तो 1 कहाँ से आता है? आंतरिक वास्तविक आकार () विधि को आकार के रूप में कहा जाता है () को नकली (या ठूंसा हुआ) नहीं कहा जाता है और इसलिए हम कह सकते हैं कि प्रवेश वास्तविक वस्तु में जोड़ा गया था।

स्रोत: http://www.baeldung.com/mockito-spy + self notes


1
क्या आपका मतलब आकार () 1 नहीं है?
काले

पहले उदाहरण में, क्यों mockedList.size()वापस लौट रहा है 0अगर उस विधि को या तो बाहर नहीं निकाला गया है? क्या यह केवल एक डिफ़ॉल्ट मान है जो विधि का रिटर्न प्रकार देता है?
माइक

@mike: mockedList.size()रिटर्न एक intकी और डिफ़ॉल्ट मान intजावा में 0 है। यदि आप निष्पादन के assertEquals(0, mockedList.size());बाद प्रयास करते हैं mockedList.clear();, तो परिणाम वही रहता है।
realPK

2
यह उत्तर अच्छी तरह से और बस लिखा गया है और मुझे आखिरकार नकली और जासूस के बीच अंतर को समझने में मदद मिली। अच्छा है।
पेसा

38

यदि 8 विधियों के साथ कोई ऑब्जेक्ट है और आपके पास एक परीक्षण है, जहां आप 7 वास्तविक तरीकों को कॉल करना चाहते हैं और एक विधि को स्टब करते हैं, तो आपके पास दो विकल्प हैं:

  1. एक मॉक का उपयोग करते हुए आपको इसे 7 callRealMethod और स्टब एक विधि को लागू करके सेट करना होगा
  2. spyआपको एक विधि का उपयोग करके इसे स्थापित करना होगा

आधिकारिक दस्तावेज पर doCallRealMethodआंशिक mocks के लिए एक जासूस का उपयोग कर सिफारिश की।

आंशिक मोक्स के बारे में अधिक जानने के लिए javadoc spy (ऑब्जेक्ट) भी देखें। Mockito.spy () आंशिक नकली बनाने का एक अनुशंसित तरीका है। इसका कारण यह है कि वास्तविक तरीके सही तरीके से निर्मित वस्तु के खिलाफ कहे जाते हैं क्योंकि आप जासूसी () पद्धति से पारित वस्तु के निर्माण के लिए जिम्मेदार हैं।


5

जब आप विरासत कोड के लिए इकाई परीक्षण बनाना चाहते हैं तो स्पाई उपयोगी हो सकता है ।

मैंने यहां एक रन करने योग्य उदाहरण बनाया है https://www.surasint.com/mockito-with-spy/ , मैं इसमें से कुछ को कॉपी करता हूं।

यदि आपके पास इस कोड जैसा कुछ है:

public void transfer(  DepositMoneyService depositMoneyService, WithdrawMoneyService withdrawMoneyService, 
             double amount, String fromAccount, String toAccount){
    withdrawMoneyService.withdraw(fromAccount,amount);
    depositMoneyService.deposit(toAccount,amount);
}

आपको जासूसी की आवश्यकता नहीं हो सकती है क्योंकि आप केवल जमा राशि जमा कर सकते हैं

लेकिन कुछ के साथ, विरासत कोड, निर्भरता इस तरह कोड में है:

    public void transfer(String fromAccount, String toAccount, double amount){

        this.depositeMoneyService = new DepositMoneyService();
        this.withdrawMoneyService = new WithdrawMoneyService();

        withdrawMoneyService.withdraw(fromAccount,amount);
        depositeMoneyService.deposit(toAccount,amount);
    }

हां, आप पहले कोड में बदल सकते हैं लेकिन फिर एपीआई बदल दिया जाता है। यदि इस विधि का उपयोग कई स्थानों पर किया जा रहा है, तो आपको उन सभी को बदलना होगा।

वैकल्पिक यह है कि आप इस तरह निर्भरता निकाल सकते हैं:

    public void transfer(String fromAccount, String toAccount, double amount){
        this.depositeMoneyService = proxyDepositMoneyServiceCreator();
        this.withdrawMoneyService = proxyWithdrawMoneyServiceCreator();

        withdrawMoneyService.withdraw(fromAccount,amount);
        depositeMoneyService.deposit(toAccount,amount);
    }
    DepositMoneyService proxyDepositMoneyServiceCreator() {
        return new DepositMoneyService();
    }

    WithdrawMoneyService proxyWithdrawMoneyServiceCreator() {
        return new WithdrawMoneyService();
    }

तो आप इस तरह से निर्भरता इंजेक्षन जासूस का उपयोग कर सकते हैं:

DepositMoneyService mockDepositMoneyService = mock(DepositMoneyService.class);
        WithdrawMoneyService mockWithdrawMoneyService = mock(WithdrawMoneyService.class);

    TransferMoneyService target = spy(new TransferMoneyService());

    doReturn(mockDepositMoneyService)
            .when(target).proxyDepositMoneyServiceCreator();

    doReturn(mockWithdrawMoneyService)
            .when(target).proxyWithdrawMoneyServiceCreator();

ऊपर दिए गए लिंक में अधिक विस्तार।


0

Mockएक नंगी दोहरी वस्तु है। इस ऑब्जेक्ट में समान विधियां हस्ताक्षर हैं, लेकिन बोध रिक्त है और डिफ़ॉल्ट मान लौटाता है - 0 और अशक्त

Spyएक क्लोन डबल ऑब्जेक्ट है। नई वस्तु को किसी वास्तविक वस्तु के आधार पर क्लोन किया जाता है लेकिन आपके पास इसका मजाक उड़ाने की संभावना होती है

class A {

    String foo1() {
        foo2();
        return "RealString_1";
    }

    String foo2() {
        return "RealString_2";
    }

    void foo3() {
        foo4();
    }

    void foo4() {

    }
}
@Test
public void testMockA() {

    //given
    A mockA = Mockito.mock(A.class);
    Mockito.when(mockA.foo1()).thenReturn("MockedString");

    //when
    String result1 = mockA.foo1();
    String result2 = mockA.foo2();

    //then
    assertEquals("MockedString", result1);
    assertEquals(null, result2);

    //Case 2
    //when
    mockA.foo3();

    //then
    verify(mockA).foo3();
    verify(mockA, never()).foo4();
}

@Test
public void testSpyA() {
    //given
    A spyA = Mockito.spy(new A());

    Mockito.when(spyA.foo1()).thenReturn("MockedString");

    //when
    String result1 = spyA.foo1();
    String result2 = spyA.foo2();

    //then
    assertEquals("MockedString", result1);
    assertEquals("RealString_2", result2);

    //Case 2
    //when
    spyA.foo3();

    //then
    verify(spyA).foo3();
    verify(spyA).foo4();
}

[परीक्षण दोहरे प्रकार]

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