2016-08-12 13 views
8

के साथ एक सिंगलटन का मज़ाक उड़ाते हुए मुझे कुछ विरासत कोड का परीक्षण करने की आवश्यकता है, जो एक विधि कॉल में सिंगलटन का उपयोग करता है। परीक्षण का उद्देश्य यह सुनिश्चित करना है कि क्लॉस सेंडर टेस्ट सिंगलेट्स विधि को कॉल करता है। मैंने SO पर समान प्रश्न देखे हैं, लेकिन सभी उत्तरों को अन्य निर्भरताओं (विभिन्न परीक्षण ढांचे) की आवश्यकता होती है - दुर्भाग्यवश मैं मॉकिटो और जुनीट का उपयोग करने तक सीमित हूं, लेकिन यह इस तरह के लोकप्रिय ढांचे के साथ पूरी तरह से संभव होना चाहिए।मॉकिटो

सिंगलटन:

public class FormatterService { 

    private static FormatterService INSTANCE; 

    private FormatterService() { 
    } 

    public static FormatterService getInstance() { 
     if (INSTANCE == null) { 
      INSTANCE = new FormatterService(); 
     } 
     return INSTANCE; 
    } 

    public String formatTachoIcon() { 
     return "URL"; 
    } 

} 

परीक्षण के अंतर्गत वर्ग:

public class DriverSnapshotHandler { 

    public String getImageURL() { 
     return FormatterService.getInstance().formatTachoIcon(); 
    } 

} 

इकाई परीक्षण:

public class TestDriverSnapshotHandler { 

    private FormatterService formatter; 

    @Before 
    public void setUp() { 

     formatter = mock(FormatterService.class); 

     when(FormatterService.getInstance()).thenReturn(formatter); 

     when(formatter.formatTachoIcon()).thenReturn("MockedURL"); 

    } 

    @Test 
    public void testFormatterServiceIsCalled() { 

     DriverSnapshotHandler handler = new DriverSnapshotHandler(); 
     handler.getImageURL(); 

     verify(formatter, atLeastOnce()).formatTachoIcon(); 

    } 

} 

विचार खतरनाक सिंगलटन से अपेक्षित व्यवहार कॉन्फ़िगर करने के लिए किया गया था, चूंकि परीक्षण के तहत कक्षा इसे प्राप्त करने के लिए कॉल करेगा और फिर प्रारूप TachoIcon विधियों। दुर्भाग्य से यह एक त्रुटि संदेश के साथ विफल:

when() requires an argument which has to be 'a method call on a mock'. 
+0

तुम भी PowerMock का उपयोग किए बिना Mockito में ऐसा नहीं कर सकते, जब तक आप अपनी वर्गों में से एक refactor। लेकिन मुझे यकीन नहीं है कि आप क्यों चाहते हैं। आप यूनिट एक विधि के साथ एक विधि का परीक्षण कर रहे हैं, और कोई आंतरिक तर्क नहीं है। यह असफल नहीं हो सकता है। अपने परीक्षण प्रयास को कहीं और खर्च करें। –

+0

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

उत्तर

9

क्या आप पूछ रहे हैं संभव है क्योंकि अपनी विरासत कोड किसी स्थिर विधि getInstance() पर निर्भर करता है और Mockito स्थिर तरीकों नकली करने की अनुमति नहीं है, इसलिए निम्न पंक्ति काम नहीं करेगा

when(FormatterService.getInstance()).thenReturn(formatter); 

2 तरीके हैं नहीं है इस समस्या को हल:

  1. ऐसे PowerMock रूप में एक अलग मजाक उपकरण,, कि स्थिर तरीकों उपहास करने के लिए अनुमति देता है का उपयोग करें।

  2. अपने कोड को दोबारा दोहराएं, ताकि आप स्थैतिक विधि पर भरोसा न करें। कम से कम आक्रामक तरीका मैं इसे प्राप्त करने के बारे में सोच सकता हूं DriverSnapshotHandler पर एक कन्स्ट्रक्टर जोड़कर है जो FormatterService निर्भरता इंजेक्ट करता है। इस कन्स्ट्रक्टर का प्रयोग केवल परीक्षणों में किया जाएगा और आप उत्पादन कोड वास्तविक सिंगलटन उदाहरण का उपयोग करना जारी रखेंगे।

    public static class DriverSnapshotHandler { 
    
        private final FormatterService formatter; 
    
        //used in production code 
        public DriverSnapshotHandler() { 
         this(FormatterService.getInstance()); 
        } 
    
        //used for tests 
        DriverSnapshotHandler(FormatterService formatter) { 
         this.formatter = formatter; 
        } 
    
        public String getImageURL() { 
         return formatter.formatTachoIcon(); 
        } 
    } 
    

फिर, अपने परीक्षण इस तरह दिखना चाहिए:

FormatterService formatter = mock(FormatterService.class); 
when(formatter.formatTachoIcon()).thenReturn("MockedURL"); 
DriverSnapshotHandler handler = new DriverSnapshotHandler(formatter); 
handler.getImageURL(); 
verify(formatter, atLeastOnce()).formatTachoIcon(); 
+0

एक तीसरा रास्ता है कि पहचान करने के लिए किया जाएगा (शायद) सिंगलटन का मज़ाक उड़ाए बिना एक बेहतर परीक्षण लिखा जा सकता है। हम इस मामले में निश्चित रूप से नहीं जान सकते हैं, क्योंकि यह एक [XY प्रश्न] (http://xyproblem.info) है। –

0

आपका getInstance methos स्थिर है, इस प्रकार mockito का उपयोग कर मज़ाक उड़ाया नहीं किया जा सकता। http://cube-drone.com/media/optimized/172.png। ऐसा करने के लिए आप PowerMockito का उपयोग करना चाह सकते हैं। हालांकि मैं इसे इस तरह से करने की सिफारिश नहीं करता। मैं निर्भरता इंजेक्शन के माध्यम से DriverSnapshotHandler का परीक्षण होगा:

public class DriverSnapshotHandler { 

    private FormatterService formatterService; 

    public DriverSnapshotHandler(FormatterService formatterService) { 
     this.formatterService = formatterService; 
    } 

    public String getImageURL() { 
     return formatterService.formatTachoIcon(); 
    } 

} 

इकाई परीक्षण:

public class TestDriverSnapshotHandler { 

    private FormatterService formatter; 

    @Before 
    public void setUp() { 

     formatter = mock(FormatterService.class); 

     when(formatter.formatTachoIcon()).thenReturn("MockedURL"); 

    } 

    @Test 
    public void testFormatterServiceIsCalled() { 

     DriverSnapshotHandler handler = new DriverSnapshotHandler(formatter); 
     handler.getImageURL(); 

     verify(formatter, times(1)).formatTachoIcon(); 

    } 

} 

आप एक @After विधि में अशक्त करने के लिए नकली सेट कर सकते हैं। यह क्लीनर समाधान imho है।

+1

आप लाइन को हटाने की जरूरत 'जब (FormatterService.getInstance()) thenReturn (फ़ॉर्मेटर)', अन्यथा परीक्षण अभ्यस्त बेशक – noscreenname

+0

चलाने - यह एक टाइपो था, ओ) –