मॉकिटो - @Spy बनाम @ मॉक


99

मॉकिटो - मैं समझता हूं कि एक जासूस एक वस्तु पर वास्तविक तरीकों को कहता है, जबकि एक नकली दोहरे ऑब्जेक्ट पर तरीकों को बुलाता है। जब तक एक कोड गंध नहीं है, तब भी जासूसों से बचा जाना चाहिए। हालांकि, जासूस कैसे काम करते हैं और मुझे वास्तव में उनका उपयोग कब करना चाहिए? वे मॉक से कैसे अलग हैं?


2
के संभावित डुप्लिकेट mockito नकली बनाम जासूस
आरडीएस

जवाबों:


88

तकनीकी रूप से "मॉक" और "जासूस" दोनों एक विशेष प्रकार के "टेस्ट डबल्स" हैं।

मॉकिटो दुर्भाग्य से भेद को अजीब बना रहा है।

मॉकिटो में एक मॉक अन्य मॉकिंग फ्रेमवर्क में एक सामान्य मॉक है (आपको इनवॉइस स्टब करने की अनुमति देता है; अर्थात, विशिष्ट मानों को विधि कॉल से बाहर लौटाता है)।

मॉकिटो में एक स्पाई अन्य मॉकिंग फ्रेमवर्क में एक आंशिक मॉक है (ऑब्जेक्ट का हिस्सा मॉक किया जाएगा और भाग वास्तविक विधि चालान का उपयोग करेगा)।


41

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

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

तुलना के रूप में नीचे दिए गए उदाहरण पर विचार करें।

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
 
import java.util.ArrayList;
import java.util.List;
 
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
 
@RunWith(MockitoJUnitRunner.class)
public class MockSpy {
 
    @Mock
    private List<String> mockList;
 
    @Spy
    private List<String> spyList = new ArrayList();
 
    @Test
    public void testMockList() {
        //by default, calling the methods of mock object will do nothing
        mockList.add("test");

        Mockito.verify(mockList).add("test");
        assertEquals(0, mockList.size());
        assertNull(mockList.get(0));
    }
 
    @Test
    public void testSpyList() {
        //spy object will call the real method when not stub
        spyList.add("test");

        Mockito.verify(spyList).add("test");
        assertEquals(1, spyList.size());
        assertEquals("test", spyList.get(0));
    }
 
    @Test
    public void testMockWithStub() {
        //try stubbing a method
        String expected = "Mock 100";
        when(mockList.get(100)).thenReturn(expected);
 
        assertEquals(expected, mockList.get(100));
    }
 
    @Test
    public void testSpyWithStub() {
        //stubbing a spy method will result the same as the mock object
        String expected = "Spy 100";
        //take note of using doReturn instead of when
        doReturn(expected).when(spyList).get(100);
 
        assertEquals(expected, spyList.get(100));
    }
}

जब आप चिल्लाते हैं तो आप नकली या जासूसी करते हैं? यदि आप सुरक्षित रहना चाहते हैं और बाहरी सेवाओं को कॉल करने से बचते हैं और केवल यूनिट के अंदर तर्क का परीक्षण करना चाहते हैं, तो मॉक का उपयोग करें। यदि आप बाहरी सेवा को कॉल करना चाहते हैं और वास्तविक निर्भरता की कॉलिंग करते हैं, या बस कहते हैं, आप प्रोग्राम को चलाना चाहते हैं जैसा कि यह है और बस विशिष्ट तरीकों को स्टब करना है, तो जासूस का उपयोग करें। तो यह है कि मज़ाक और मॉकिटो में अंतर।


अच्छा उत्तर लेकिन यह सत्यापित करेगा () केवल एक त्रुटि पर मॉक डालेगा और तब तक परीक्षण नहीं चलाएगा जब तक आप अपनी सूचियों को @Before setUp () विधि से यहां mockList = mock (ArrayList.class) की तरह शुरू नहीं करते; spyList = spy (ArrayList.class); और यहां सुझाए गए नकली और जासूसी एनोटेशन को हटा दें। मैंने इसका परीक्षण किया है और मेरे परीक्षण अभी गुजर रहे हैं।
the_Martian

17

TL; DR संस्करण,

मॉक के साथ , यह आपके लिए एक नंगे हड्डी खोल उदाहरण बनाता है।

List<String> mockList = Mockito.mock(ArrayList.class);

जासूस के साथ आप मौजूदा उदाहरण पर आंशिक रूप से नकली कर सकते हैं

List<String> spyList = Mockito.spy(new ArrayList<String>());

स्पाई के लिए विशिष्ट उपयोग का मामला: कक्षा में एक पैरामीटर निर्मित निर्माता है, आप पहले ऑब्जेक्ट बनाना चाहते हैं।


14

मैंने यहां एक रन करने योग्य उदाहरण बनाया है 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();

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


13

शुरू करने के लिए सबसे अच्छी जगह शायद मॉकिटो के लिए डॉक्स है

एक सामान्य नोट पर मॉकिटो मॉक आपको स्टब्स बनाने की अनुमति देता है।

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

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

मॉकिटो जासूस आपको यह जांचने देता है कि कोई विधि अन्य विधियों को कॉल करती है या नहीं। परीक्षण के तहत विरासत कोड प्राप्त करने की कोशिश करते समय यह बहुत उपयोगी हो सकता है।

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


7

संक्षेप में:

@Spyऔर @Mockकोड के परीक्षण में भारी उपयोग किया जाता है, लेकिन डेवलपर्स उन मामलों में भ्रमित करते हैं जब उनमें से एक का उपयोग करना होता है और इस प्रकार डेवलपर्स @Mockसुरक्षित होने का उपयोग करते हुए समाप्त हो जाते हैं।

  • @Mockजब आप वास्तव में उस पद्धति को कॉल किए बिना केवल कार्यक्षमता का बाहरी रूप से परीक्षण करना चाहते हैं, तब उपयोग करें ।
  • का प्रयोग करें @Spyजब आप कार्यक्षमता का परीक्षण करना चाहते हैं बाह्य + आंतरिक रूप से बहुत विधि बुलाया जा रहा है।

नीचे उदाहरण है जहां मैंने अमेरिका में Election20xx का परिदृश्य लिया है ।

मतदाताओं को VotersOfBelow21और के अनुसार विभाजित किया जा सकता है VotersOfABove21

आदर्श एग्जिट पोल में कहा गया है कि ट्रम्प चुनाव जीतेंगे क्योंकि VotersOfBelow21और VotersOfABove21दोनों ट्रम्प को वोट देंगे, " हम राष्ट्रपति ट्रम्प निर्वाचित "

लेकिन यह वास्तविक परिदृश्य नहीं है:

दोनों आयु वर्ग के मतदाताओं ने ट्रम्प को वोट दिया क्योंकि उनके पास श्री ट्रम्प के अलावा कोई अन्य प्रभावी विकल्प नहीं था।

तो आप इसे कैसे टेस्ट करते हैं ??

public class VotersOfAbove21 {
public void weElected(String myVote){
  System.out.println("Voters of above 21 has no Choice Than Thrump in 20XX ");
}
}

public class VotersOfBelow21 {
  public void weElected(String myVote){
    System.out.println("Voters of below 21 has no Choice Than Thrump in 20XX");
  }
}

public class ElectionOfYear20XX {
  VotersOfAbove21 votersOfAbove21;
  VotersOfBelow21 votersOfBelow21;
  public boolean weElected(String WeElectedTrump){
    votersOfAbove21.weElected(WeElectedTrump);
    System.out.println("We elected President Trump ");

    votersOfBelow21.weElected(WeElectedTrump);
    System.out.println("We elected President Trump ");
    return true;
  }

}

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

अब ElectionOfYear20XX कहते हैं कि ट्रम्प जीत गए क्योंकि दोनों आयु वर्ग ने उन्हें भारी मत दिया।

अगर हम ElectionOfYear20XX@Mock के साथ टेस्ट करने वाले थे , तो हो सकता है कि ट्रम्प की जीत की असली वजह हमें नहीं मिल पाएगी, हम सिर्फ बाहरी कारण को परखेंगे।

यदि हम ElectionOfYear20XX@Spy के साथ परीक्षण करते हैं , तो हमें असली कारण मिलता है कि ट्रम्प ने बाहरी एक्जिट पोल परिणामों के साथ आंतरिक रूप से + बाहरी रूप से जीत हासिल की।


हमारी ELectionOfYear20XX_Testकक्षा:

@RunWith(MockitoJUnitRunner.class)
public class ELectionOfYear20XX_Test {

  @Mock
  VotersOfBelow21 votersOfBelow21;
  @Mock
  VotersOfAbove21 votersOfAbove21;
  @InjectMocks
  ElectionOfYear20XX electionOfYear20XX;
  @Test
  public void testElectionResults(){
    Assert.assertEquals(true,electionOfYear20XX.weElected("No Choice"));
  }

}

यह सिर्फ लॉजिक टेस्ट के परिणाम यानी बाहरी जाँच का उत्पादन करना चाहिए :

We elected President Trump 
We elected President Trump 

@Spyबाहरी पद्धति के साथ-साथ आंतरिक रूप से वास्तविक विधि आह्वान के साथ परीक्षण ।

@RunWith(MockitoJUnitRunner.class)
public class ELectionOfYear20XX_Test {

  @Spy
  VotersOfBelow21 votersOfBelow21;
  @Spy
  VotersOfAbove21 votersOfAbove21;
  @InjectMocks
  ElectionOfYear20XX electionOfYear20XX;
  @Test
  public void testElectionResults(){
    Assert.assertEquals(true,electionOfYear20XX.weElected("No Choice"));
  }

}

आउटपुट:

Voters of above 21 has no Choice Than Thrump in 20XX 
We elected President Trump 
Voters of below 21 has no Choice Than Thrump in 20XX
We elected President Trump 

6

मुझे इस सिफारिश की सादगी पसंद है:

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

स्रोत: https://javapointers.com/tutorial/difference-between-spy-and-mock-in-ockock/

एक सामान्य अंतर है:

  • यदि आप एक निर्भरता की विधि (एस) को सीधे स्टुब करना चाहते हैं, तो वह निर्भरता मॉक करें
  • यदि आप किसी निर्भरता में डेटा को स्टब करना चाहते हैं ताकि उसके सभी तरीके परीक्षण मूल्यों को वापस कर दें, जिनकी आपको आवश्यकता है, तो उस निर्भरता को जासूसी करें

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