मॉकिटो के साथ विशिष्ट प्रकार की सूची पर कब्जा कैसे करें


301

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

ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);

8
मुझे लगता है कि यहां ठोस सूची कार्यान्वयन का उपयोग करना एक भयानक विचार है ( ArrayList)। आप हमेशा Listइंटरफ़ेस का उपयोग कर सकते हैं , और यदि आप इस तथ्य का प्रतिनिधित्व करना चाहते हैं, कि यह सहसंयोजक है, तो आप उपयोग कर सकते हैं extends:ArgumentCaptor<? extends List<SomeType>>
दसवीं

जवाबों:


533

नेस्टेड जेनरिक-समस्या से बचा जा सकता है @ कप्तान के एनोटेशन :

public class Test{

    @Mock
    private Service service;

    @Captor
    private ArgumentCaptor<ArrayList<SomeType>> captor;

    @Before
    public void init(){
        MockitoAnnotations.initMocks(this);
    }

    @Test 
    public void shouldDoStuffWithListValues() {
        //...
        verify(service).doStuff(captor.capture()));
    }
}

70
मैं का उपयोग करना पसंद MockitoAnnotations.initMocks(this)में @Beforeके बजाय विधि एक धावक का उपयोग कर कि शामिल नहीं एक और धावक उपयोग करने की क्षमता। हालाँकि, +1, एनोटेशन इंगित करने के लिए धन्यवाद।
जॉन बी

4
सुनिश्चित नहीं है कि यह उदाहरण पूरा हो गया है। मुझे ... त्रुटि: (२४०, ४०) जावा: चर बन्दी को इनिशियलाइज़ नहीं किया जा सकता है जैसे कि मुझे नीचे दसियों का जवाब पसंद है
माइकल डौसमैन

1
मैं उसी मुद्दे में भाग गया, और इस ब्लॉग पोस्ट को पाया जिसने मुझे थोड़ी मदद की: blog.jdriven.com/2012/10/… । इसमें आपकी कक्षा पर एनोटेशन डालने के बाद MockitoAnnotations.initMocks का उपयोग करने का चरण शामिल है। एक बात मैंने देखी कि आप इसे किसी स्थानीय चर के भीतर नहीं रख सकते।
स्लोपऑक

1
@ chamzz.dot ArgumentCaptor <ArrayList <SomeType >> captor; पहले से ही "SomeType" की एक सरणी कैप्चर कर रहा है <- वह एक विशिष्ट प्रकार है, है न?
मिगुएल आर। सांता्टेला

1
मैं आमतौर पर कैप्टन घोषणा में ArrayList के बजाय सूची को प्राथमिकता देता हूं: ArgumentCaptor <List <SomeType >> captor;
मिगुएल आर। सांताटेला

146

हाँ, यह सामान्य सामान्य समस्या है, मॉकिटो-विशिष्ट नहीं।

इसके लिए कोई क्लास ऑब्जेक्ट नहीं है ArrayList<SomeType>, और इस प्रकार आप इस तरह के ऑब्जेक्ट को सुरक्षित रूप से टाइप नहीं कर सकते हैं Class<ArrayList<SomeType>>

आप ऑब्जेक्ट को सही प्रकार से डाल सकते हैं:

Class<ArrayList<SomeType>> listClass =
              (Class<ArrayList<SomeType>>)(Class)ArrayList.class;
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(listClass);

यह असुरक्षित डाले के बारे में कुछ चेतावनी देगा, और निश्चित रूप से अपने ArgumentCaptor वास्तव में बीच अंतर नहीं कर सकते हैं ArrayList<SomeType>और ArrayList<AnotherType>हो सकता है तत्वों का निरीक्षण के बिना।

(के रूप में, अन्य जवाब में बताया गया है, जबकि यह एक सामान्य जेनरिक समस्या है, वहाँ के साथ प्रकार-सुरक्षा की समस्या के लिए एक Mockito विशेष समाधान है @Captorएनोटेशन। यह अभी भी एक के बीच भेद नहीं कर सकते हैं ArrayList<SomeType>और एक ArrayList<OtherType>।)

संपादित करें:

दसियों की टिप्पणी पर भी एक नज़र डालें । आप Pa canlo Ebermann से मूल कोड को इसमें बदल सकते हैं (बहुत सरल)

final ArgumentCaptor<List<SomeType>> listCaptor
        = ArgumentCaptor.forClass((Class) List.class);

49
आपके द्वारा दिखाए गए उदाहरण को सरल बनाया जा सकता है, इस तथ्य के आधार पर कि जावा स्थिर विधि कॉल के लिए प्रकार की खोज करता है:ArgumentCaptor<List<SimeType>> argument = ArgumentCaptor.forClass((Class) List.class);
दसवीं

4
अनियंत्रित या असुरक्षित संचालन चेतावनी के उपयोग को अक्षम करने के लिए , @SuppressWarnings("unchecked")तर्क कैप्चर परिभाषा रेखा के ऊपर एनोटेशन का उपयोग करें । इसके अलावा, कास्टिंग Classनिरर्थक है।
एमआरटीएस

1
Classमेरे परीक्षणों में कास्टिंग निरर्थक नहीं है।
विम डेलाउवे

16

यदि आप पुराने जावा-शैली (गैर प्रकार के सुरक्षित सामान्य) शब्दार्थ से डरते नहीं हैं, तो यह भी काम करता है और यथोचित सरल है:

ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);
verify(subject.method(argument.capture()); // run your code
List<SomeType> list = argument.getValue(); // first captured List, etc.

2
चेतावनियों को निष्क्रिय करने की घोषणा से पहले आप @SuppressWarnings ("rawtypes") जोड़ सकते हैं।
पल्किनोव

9
List<String> mockedList = mock(List.class);

List<String> l = new ArrayList();
l.add("someElement");

mockedList.addAll(l);

ArgumentCaptor<List> argumentCaptor = ArgumentCaptor.forClass(List.class);

verify(mockedList).addAll(argumentCaptor.capture());

List<String> capturedArgument = argumentCaptor.<List<String>>getValue();

assertThat(capturedArgument, hasItem("someElement"));

4

@ दसियों की और @ पल्किनो की टिप्पणियों (@ कुगरडैप के लिए भी कुदोस) के आधार पर, सूची तर्क कैप्चर बनाने के लिए निम्नलिखित एक सरल उपाय है जो "अनियंत्रित या असुरक्षित संचालन" चेतावनी को निष्क्रिय करता है।

@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
    ArgumentCaptor.forClass(List.class);

पूर्ण उदाहरण यहाँ और इसी पास CI निर्माण और परीक्षण रन यहाँ

हमारी टीम कुछ समय से हमारे यूनिट परीक्षणों में इसका उपयोग कर रही है और यह हमारे लिए सबसे सीधा समाधान है।


2

जूनियर के पुराने संस्करण के लिए, आप कर सकते हैं

Class<Map<String, String>> mapClass = (Class) Map.class;
ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(mapClass);

1

मेरे एंड्रॉइड ऐप में परीक्षण गतिविधि के साथ मेरे पास एक ही मुद्दा था। मैंने इस्तेमाल किया ActivityInstrumentationTestCase2और MockitoAnnotations.initMocks(this);काम नहीं किया। मैंने क्रमशः क्षेत्र के साथ एक अन्य वर्ग के साथ इस मुद्दे को हल किया। उदाहरण के लिए:

class CaptorHolder {

        @Captor
        ArgumentCaptor<Callback<AuthResponse>> captor;

        public CaptorHolder() {
            MockitoAnnotations.initMocks(this);
        }
    }

फिर, गतिविधि परीक्षण विधि में:

HubstaffService hubstaffService = mock(HubstaffService.class);
fragment.setHubstaffService(hubstaffService);

CaptorHolder captorHolder = new CaptorHolder();
ArgumentCaptor<Callback<AuthResponse>> captor = captorHolder.captor;

onView(withId(R.id.signInBtn))
        .perform(click());

verify(hubstaffService).authorize(anyString(), anyString(), captor.capture());
Callback<AuthResponse> callback = captor.getValue();

0

इस सटीक समस्या के बारे में मॉकिटो के गिटहब में एक खुला मुद्दा है।

मुझे एक साधारण हल मिला है जो आपको अपने परीक्षणों में एनोटेशन का उपयोग करने के लिए मजबूर नहीं करता है:

import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.MockitoAnnotations;

public final class MockitoCaptorExtensions {

    public static <T> ArgumentCaptor<T> captorFor(final CaptorTypeReference<T> argumentTypeReference) {
        return new CaptorContainer<T>().captor;
    }

    public static <T> ArgumentCaptor<T> captorFor(final Class<T> argumentClass) {
        return ArgumentCaptor.forClass(argumentClass);
    }

    public interface CaptorTypeReference<T> {

        static <T> CaptorTypeReference<T> genericType() {
            return new CaptorTypeReference<T>() {
            };
        }

        default T nullOfGenericType() {
            return null;
        }

    }

    private static final class CaptorContainer<T> {

        @Captor
        private ArgumentCaptor<T> captor;

        private CaptorContainer() {
            MockitoAnnotations.initMocks(this);
        }

    }

}

यहां होता है कि हम एक नया वर्ग पैदा करते हैं साथ@Captor एनोटेशन और इसे में क़ैदी बनानेवाला इंजेक्षन। फिर हम बस कैप्चर को निकालते हैं और इसे अपनी स्थैतिक विधि से वापस करते हैं।

अपने परीक्षण में आप इसका उपयोग इस तरह कर सकते हैं:

ArgumentCaptor<Supplier<Set<List<Object>>>> fancyCaptor = captorFor(genericType());

या सिंटैक्स के साथ जो जैक्सन का है TypeReference:

ArgumentCaptor<Supplier<Set<List<Object>>>> fancyCaptor = captorFor(
    new CaptorTypeReference<Supplier<Set<List<Object>>>>() {
    }
);

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

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