सामान्य मापदंडों के साथ मॉकिटो कक्षाओं का उपयोग करना


280

क्या जेनेरिक मापदंडों के साथ एक वर्ग का मजाक उड़ाने का एक साफ तरीका है? कहते हैं कि मुझे एक वर्ग का मज़ाक उड़ाना होगा Foo<T>जो मुझे एक ऐसी विधि में पारित करने की आवश्यकता है जो उम्मीद करता है कि ए Foo<Bar>। मैं निम्नलिखित आसानी से पर्याप्त कर सकते हैं:

Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

मान लें getValue()कि सामान्य प्रकार देता है T। लेकिन जब मुझे बाद में उम्मीद है कि इसे एक विधि के रूप में पारित किया जाएगा, तो बिल्ली के बच्चे होने वाले हैं Foo<Bar>। क्या ऐसा करने का एकमात्र साधन कास्टिंग है?

जवाबों:


280

मुझे लगता है कि आपको इसे कास्ट करने की आवश्यकता है, लेकिन यह बहुत बुरा नहीं होना चाहिए:

Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue()).thenReturn(new Bar());

34
हां, लेकिन आपके पास अभी भी चेतावनी है। क्या चेतावनी से बचना संभव है?
odwl

12
@SuppressWarnings ("अनियंत्रित")
क्वालिडैफियल

18
मुझे लगता है कि यह पूरी तरह से स्वीकार्य है क्योंकि हम एक इकाई परीक्षण में एक नकली वस्तु के बारे में बात कर रहे हैं।
मैगनीलेक्स

1
@demaniak यह बिल्कुल काम नहीं करता है। उस संदर्भ में तर्क मिलान का उपयोग नहीं किया जा सकता है।
Krzysztof Krasoń

1
@demaniak यह केवल ठीक संकलन करेगा, लेकिन परीक्षण चलाने पर यह InvalidUseOfMatchersException (जो एक
RuntimeException है

277

इसके इर्द-गिर्द एक और तरीका @Mockइसके बजाय एनोटेशन का उपयोग करना है। सभी मामलों में काम नहीं करता है, लेकिन बहुत कामुक लगता है :)

यहाँ एक उदाहरण है:

@RunWith(MockitoJUnitRunner.class)
public class FooTests {

    @Mock
    public Foo<Bar> fooMock;

    @Test
    public void testFoo() {
        when(fooMock.getValue()).thenReturn(new Bar());
    }
}

के MockitoJUnitRunnerसाथ एनोटेट किए गए फ़ील्ड को इनिशियलाइज़ करता है @Mock


3
यह 1.9.5 में पदावनत है। :( मेरे लिए बहुत क्लीनर लगता है।
कोड Novitiate

12
@CodeNovitiate मैं MockitoJUnitRunner और मॉक पर 1.9.5 में कोई भी अपग्रेडेशन एनोटेशन नहीं पा सका। तो, पदावनत क्या है? (हाँ, org.mockito.MockitoAnnotations.Mock पदावनत है, लेकिन आपको org.mockito.Mock का उपयोग करना चाहिए)
neu242

12
अच्छा किया, यह मेरे लिए पूरी तरह से काम किया। यह सिर्फ "कामुक" नहीं है, यह उपयोग किए बिना एक चेतावनी से बचा जाता है SuppressWarnings। चेतावनी एक कारण के लिए मौजूद है, उन्हें दबाने की आदत में नहीं होना बेहतर है। धन्यवाद!
निकोल

4
एक बात है जो मुझे @Mockइसके बजाय उपयोग करने के बारे में पसंद नहीं है mock(): निर्माण समय के दौरान फ़ील्ड अभी भी शून्य हैं, इसलिए मैं उस समय निर्भरता नहीं डाल सकता हूं और खेतों को अंतिम नहीं बना सकता हूं। पूर्व निश्चित रूप से एक @Before-नोटेड विधि द्वारा हल किया जा सकता है ।
रुडिगर शूल्ज

3
दीक्षा के लिए सिर्फ MockitoAnnotations.initMocks (यह) पर कॉल करें;
बोरजब

42

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

private interface FooBar extends Foo<Bar>
{
}

उन स्थितियों में जहां फू एक गैर-अंतिम वर्ग है, आप निम्नलिखित कोड के साथ वर्ग का विस्तार कर सकते हैं और एक ही काम कर सकते हैं:

public class FooBar extends Foo<Bar>
{
}

फिर आप निम्नलिखित कोड के साथ उपरोक्त उदाहरणों में से किसी एक का उपभोग कर सकते हैं:

Foo<Bar> mockFoo = mock(FooBar.class);
when(mockFoo.getValue()).thenReturn(new Bar());

4
बशर्ते Fooएक इंटरफ़ेस या गैर-अंतिम वर्ग है, यह एक उचित रूप से सुरुचिपूर्ण समाधान प्रतीत होता है। धन्यवाद।
टिम क्लेम्सन्स

मैंने गैर-अंतिम कक्षाओं के लिए उदाहरणों को शामिल करने के लिए उत्तर को अपडेट किया। आदर्श रूप से आप एक इंटरफेस के खिलाफ कोडिंग करेंगे, लेकिन यह हमेशा ऐसा नहीं होगा। अच्छी पकड़!
डिंगेलटन

16

एक परीक्षण उपयोगिता विधि बनाएँ । यदि आपको एक से अधिक बार इसकी आवश्यकता है तो विशेष रूप से उपयोगी है।

@Test
public void testMyTest() {
    // ...
    Foo<Bar> mockFooBar = mockFoo();
    when(mockFooBar.getValue).thenReturn(new Bar());

    Foo<Baz> mockFooBaz = mockFoo();
    when(mockFooBaz.getValue).thenReturn(new Baz());

    Foo<Qux> mockFooQux = mockFoo();
    when(mockFooQux.getValue).thenReturn(new Qux());
    // ...
}

@SuppressWarnings("unchecked") // still needed :( but just once :)
private <T> Foo<T> mockFoo() {
    return mock(Foo.class);
}

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

1
@WilliamDutton को static <T> T genericMock(Class<? super T> classToMock) { return (T)mock(classToMock); }एक भी दमन की आवश्यकता नहीं है :) लेकिन सावधान, Integer num = genericMock(Number.class)संकलित करें, लेकिन फेंकता है ClassCastException। यह केवल सबसे आम G<P> mock = mock(G.class)मामले के लिए उपयोगी है ।
TWStStrrob

6

मैं मानता हूं कि किसी को कक्षाओं या विधियों में चेतावनियों को नहीं दबाना चाहिए क्योंकि कोई दूसरे को भूल सकता है, अनजाने में चेतावनी को दबा सकता है। लेकिन IMHO यह एक चेतावनी को दबाने के लिए बिल्कुल उचित है जो कोड की केवल एक पंक्ति को प्रभावित करता है।

@SuppressWarnings("unchecked")
Foo<Bar> mockFoo = mock(Foo.class);

3

यहां एक दिलचस्प मामला है: विधि सामान्य संग्रह प्राप्त करती है और एक ही आधार प्रकार का सामान्य संग्रह लौटाती है। उदाहरण के लिए:

Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);

इस विधि को मॉकिटो anyCollectionOf मिलानकर्ता और उत्तर के संयोजन के साथ मजाक किया जा सकता है।

when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
     new Answer<Collection<Assertion>>() {
         @Override
         public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
             return new ArrayList<Assertion>();
         }
     });
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.