2012-10-27 12 views
6

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

public interface Reader { 
    int readInt(); 
    short readShort(); 
} 

कक्षा का परीक्षण डेटा स्ट्रीम से विभिन्न डेटा संरचनाओं में पढ़ा जाता है।

public class SomethingsTest { 
    @Test 
    public void testSomethings() { 
     Reader reader = Mockito.mock(Reader.class); 

     readCount(reader, 2); 
     readSomething(reader, 1, 2, 3); 
     readSomething(reader, 4, 5, 6); 

     Somethings somethings = new Somethings(reader); 
     Assert.assertEqual(2, somethings.size()); 
     Assert.assertEquals(new Something(1, 2, 3), somethings.somethings.get(0)); 
     Assert.assertEquals(new Something(4, 5, 6), somethings.somethings.get(1)); 
    } 

    private void readCount(Reader reader, int count) { 
     when(reader.readInt()).thenReturn(count); 
    } 

    private void readSomething(Reader reader, int a, short b, int c) { 
     when(reader.readInt()).thenReturn(a); 
     when(reader.readShort()).thenReturn(b); 
     when(reader.readInt()).thenReturn(c); 
    } 
} 

दुर्भाग्य से, यह काम नहीं करता है: उदाहरण के लिए,

public class Somethings { 
    public List<Something> somethings; 

    public Somethings(Reader reader) { 
     somethings = new List<Something>(); 
     int count = reader.readInt(); 
     for (int i=0; i<count; i++) { 
      somethings.add(readSomething(reader)); 
     } 
    } 

    private Something readSomething(Reader reader) { 
     int a = reader.readInt(); 
     short b = reader.readShort(); 
     int c = reader.readInt(); 
     return new Something(a, b, c); 
    } 
} 

और अंत में, मैं अपने परीक्षण किया है। reader.readInt() हमेशा प्रत्येक आमंत्रण के लिए 6 लौटाता है। और मैं समझता हूं कि यह क्यों लौटाता है 6. यह मेरा सवाल नहीं है।

परीक्षणों को ठीक करने के लिए मैं दो विकल्प सोच सकता हूं, लेकिन मुझे विशेष रूप से किसी एक को पसंद नहीं है।

पहला विकल्प की तरह कुछ होगा:

public class SomethingsTest { 
    @Test 
    public void testSomethings() { 
     Reader reader = Mockito.mock(Reader.class); 

     when(reader.readInt()) 
      .thenReturn(2) 
      .thenReturn(1) 
      .thenReturn(3) 
      .thenReturn(4) 
      .thenReturn(6); 
     when(reader.readShort()) 
      .thenReturn(2) 
      .thenReturn(5); 

     Somethings somethings = new Somethings(reader); 
     Assert.assertEqual(2, somethings.size()); 
     Assert.assertEquals(new Something(1, 2, 3), somethings.somethings.get(0)); 
     Assert.assertEquals(new Something(4, 5, 6), somethings.somethings.get(1)); 
    } 
} 

यह काम करना चाहिए, लेकिन यह बहुत अखंड और गंदा है। यह देखना मुश्किल है कि कौन सी वापसी किस संरचना के टुकड़े के लिए है, क्योंकि वे सभी बिना किसी संरचना के इंटरमीस्ड हैं।

public class SomethingsTest { 
    @Test 
    public void testSomethings() { 
     Reader reader = Mockito.mock(Reader.class); 

     NewOngoingStubbing readIntStub = when(reader.readInt()); 
     NewOngoingStubbing readShortStub = when(reader.readShort()); 

     readCount(readIntStub, 2); 
     readSomething(readIntStub, readShortStub, 1, 2, 3); 
     readSomething(readIntStub, readShortStub, 4, 5, 6); 

     Somethings somethings = new Somethings(reader); 
     Assert.assertEqual(2, somethings.size()); 
     Assert.assertEquals(new Something(1, 2, 3), somethings.somethings.get(0)); 
     Assert.assertEquals(new Something(4, 5, 6), somethings.somethings.get(1)); 
    } 

    private void readCount(NewOngoingStubbing readIntStub, int count) { 
     readIntStub.thenReturn(count); 
    } 

    private void readSomething(NewOngoingStubbing readIntStub, 
      NewOngoingStubbing readShortStub, int a, short b, int c) { 
     readIntStub.thenReturn(a); 
     readShortStub.thenReturn(b); 
     readIntStub.thenReturn(c); 
    } 
} 

यह कम से कम मूल की संरचना को बनाए रखता है, लेकिन प्रत्येक विधि के लिए एक अलग वस्तु पारित करने के लिए हो रही फोन आप टोंटदार पर बनाना चाहते:

दूसरा मैं के बारे में सोच सकते हैं विकल्प कुछ की तरह है वस्तु है ... उह।

इस परीक्षण को करने का सबसे साफ तरीका क्या होगा? क्या कोई विकल्प है जो मैं यहां याद कर रहा हूं? कुछ कार्यक्षमता जो मैं लीवरेज कर सकता हूं? मैंने आज रात मॉकिटो का उपयोग करना शुरू कर दिया .. इसलिए मैं कुछ खो रहा था।

उत्तर

1

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

अपने सटीक आवश्यकताओं के आधार पर, आप उदाहरण के लिए एक Answer कि नंबरों की सूची से एक नए तत्व देता है, अनुरोध प्रकार (int या short) की परवाह किए बिना बना सकते हैं। परिवर्तनीय readList एक सदस्य हो सकता है जिसे आप अपने परिणामों को सेट करने के लिए उपयोग किए जाने वाले सभी कार्यों से एक्सेस कर सकते हैं।

final List<Integer> readList = new ArrayList<>(); 
// ... Fill readList with answers 

Answer answerFromList = new Answer() { 
    Object answer(InvocationOnMock invocation) { 
     // Remove and return first element 
     return readList.remove(0); 
    } 
} 

when(reader.readInt()).thenAnswer(answerFromList); 
when(reader.readShort()).thenAnswer(answerFromList); 

ध्यान दें कि यह Answer, ReturnElementsOf प्रदान की तरह एक बहुत कुछ है, तो आप उसका प्रयोग सीधे रूप में अच्छी तरह कर सकते हैं।

5

मॉकिटो चल रहा है मूल रूप से चल रहा है। आपका पहला उदाहरण ठीक है, लेकिन यह भी काम करना चाहिए:

when(reader.readInt()).thenReturn(2, 1, 3, 4, 6); 

प्रलेखन इसके लिए here है।

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

+0

जैसा कि मैंने उल्लेख किया है, मुझे पता है कि मेरे द्वारा उल्लेखित 2 विकल्पों में से कोई भी काम करेगा, लेकिन मुझे किसी की भी परवाह नहीं है। बस .henReturn (1) की एक श्रृंखला को बदलना .thenReturn (2) से .thenReturn (1, 2) किसी भी तरह की संरचना में सुधार नहीं करता है :) – JesusFreke

+0

इसलिए मैंने एक विकल्प के रूप में अपना खुद का रोलिंग क्यों सुझाया। – Lunivore

2

आप इससे निपटने के लिए एक कक्षा बना सकते हैं, उदा।

private static class ReaderStubber { 
    private final Reader reader = Mockito.mock(Reader.class); 
    private final NewOngoingStubbing readIntStub = when(reader.readInt());; 
    private final NewOngoingStubbing readShortStub = when(reader.readShort());; 

    public Reader getReader() { 
     return reader; 
    }  

    private void readCount(int count) { 
     readIntStub.thenReturn(count); 
    } 

    private void readSomething(int a, short b, int c) { 
     readIntStub.thenReturn(a); 
     readShortStub.thenReturn(b); 
     readIntStub.thenReturn(c); 
    } 
} 

लेकिन फिर सवाल यह है कि क्या आपको वास्तव में मॉकिटो के साथ ऐसा करने की ज़रूरत है? सबकुछ मजाक नहीं होना चाहिए। हो सकता है कि कुछ List<Integer> के साथ परीक्षण के लिए बस एक स्टब Reader लागू करना बेहतर है।


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

+0

हम्म, अच्छा विचार, हालांकि आपके पास इस मामले में मॉकिटो का उपयोग करने के बारे में कोई बात है। मैं शायद कुछ और के साथ जाऊंगा: निजी शून्य readInt (int val) {readIntStub.thenReturn (val); }। – JesusFreke