2011-12-14 17 views
19

के साथ एक बिल्डर उपहास करने के लिए मैं एक बिल्डर है:कैसे mockito

class Builder{ 
    private String name; 
    private String address; 
    public Builder setName(String name){ 
     this.name = name; 
     return this; 
    } 
    public Builder setAddress(String address){ 
     this.address = address; 
     return this; 
    } 

} 

mockito वसीयत में बिल्डर मजाक मुझे हर विधि के लिए अशक्त देता है। तो when().thenReturn का उपयोग करके प्रत्येक फ़ंक्शन को मजाक किए बिना, प्रत्येक फ़ंक्शन कॉल पर बिल्डर को खुद को वापस लाने का एक आसान तरीका है।

+2

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

+1

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

+1

क्या आप उन्हें अलग कर सकते हैं ताकि आपके पास * "गूंगा निर्माता" हो (जिसे मॉकिंग की आवश्यकता नहीं है) और फिर सर्विस पार्ट जो * * को मजाक करने की ज़रूरत है? –

उत्तर

8

आप एक चेनिंग एपीआई नकल करने के लिए RETURN_DEEP_STUBS का उपयोग कर सकते हैं।

Builder b = Mockito.mock(Builder.class, RETURNS_DEEP_STUBS); 
when(b.setName("a name").setAddress("an address")).thenReturn(b); 
assert b.setName("a name").setAddress("an address") == b; // this passes 

दुर्भाग्य से यह आप सभी विभिन्न बिल्डर मजाक "की एक सामान्य तरीके नहीं देंगे:

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

+2

यह भी एनबी कि अगर आपको "ग़लत" ऑर्डर करने और परिणाम डालने के लिए गहरी स्टब मिलती है, तो यह आपको कुछ अजीब दिखने वाले संदेश देगा, संभवतः 'java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer $ ClassWithSuperclassToWorkAroundCglibBug $$ EnhancerByMockitoWithCGLIB $$ 851828bd को नहीं डाला जा सकता है ... ' – rogerdpack

34

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

import static org.mockito.Mockito.RETURNS_DEFAULTS; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class SelfReturningAnswer implements Answer<Object>{ 

    public Object answer(InvocationOnMock invocation) throws Throwable { 
     Object mock = invocation.getMock(); 
     if(invocation.getMethod().getReturnType().isInstance(mock)){ 
      return mock; 
     } 
     else{ 
      return RETURNS_DEFAULTS.answer(invocation); 
     } 
    } 
} 

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

इस

Builder mockBuilder = mock(Builder.class, new SelfReturningAnswer()); 

की तरह अपने नकली या इस वर्ग के लिए एक निरंतर बना सकते हैं और लिखने

@Mock(answer = SELF_RETURNING) private Builder mockBuilder; 

आशा है कि मदद करता है की तरह कुछ।

+0

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

+1

हां, मुझे बिल्कुल यकीन है।मैंने उपरोक्त के रूप में आपके बिल्डर वर्ग के लिए एक परीक्षा लिखी, जहां मैंने RETURNS_DEEP_STUBS के साथ एक नकली बनाई, जिसे setAddress और setName कहा जाता है। मेरे परीक्षण ने जोर दिया कि दो विधि कॉल से लौटे दो मोड़ अलग थे। मेरा परीक्षण पास हो गया। –

+0

मेरा परीक्षण http://pastebin.com/JNPrn4ng –

12

मॉकिटो 2.0 (बीटा) के रूप में, RETURNS_SELF के लिए एक नया डिफ़ॉल्ट उत्तर है जो लगभग David Wallace's answer पर लगभग समान व्यवहार करता है। Mockito डॉक्स से उदाहरण:

@Test 
public void use_full_builder_with_terminating_method() { 
    HttpBuilder builder = mock(HttpBuilder.class, RETURNS_SELF); 
    HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder); 
    String response = "StatusCode: 200"; 

    when(builder.request()).thenReturn(response); 

    assertThat(requester.request("URI")).isEqualTo(response); 
} 

ध्यान दें कि यह Mockito वर्ग पर और Answers enum पर दोनों है, इसलिए इसे भी @Mock(answer = RETURNS_SELF) वाक्य रचना के साथ संगत होना है।

संबंधित मुद्दे