মকিতো সহ নির্দিষ্ট ধরণের একটি তালিকা কীভাবে ক্যাপচার করবেন


301

মকিটোস আর্গুমেন্টক্যাপ্টোর ব্যবহার করে নির্দিষ্ট ধরণের একটি তালিকা ক্যাপচার করার কোনও উপায় আছে কি? এটি কাজ করে না:

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

8
আমি মনে করি যে একটি ভয়ানক ধারণা এখানে কংক্রিট তালিকা বাস্তবায়ন ব্যবহার করবেন ( ArrayList)। আপনি সর্বদা Listইন্টারফেস ব্যবহার করতে পারেন , এবং যদি আপনি এই সত্যটি উপস্থাপন করতে চান যে এটি extendsArgumentCaptor<? 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/… । আপনি আপনার ক্লাসে টিকাটি লেখার পরে এটি মকিতোঅনোটেশন.ইনটমকস ব্যবহার করার জন্য একটি পদক্ষেপ অন্তর্ভুক্ত করে। একটি জিনিস আমি লক্ষ্য করেছি যে আপনি এটি স্থানীয় ভেরিয়েবলের মধ্যে রাখতে পারবেন না।
স্লোপ ওক

1
@ chamzz.dot ArgumentCaptor <অ্যারেলিস্ট <সোমেটাইপ>> বন্দী; ইতিমধ্যে "কিছু টাইপ" এর অ্যারে ক্যাপচার করছে <- এটি একটি নির্দিষ্ট ধরণের, তাই না?
মিগুয়েল আর সান্তােলা

1
আমি সাধারণত ক্যাপ্টোর ঘোষণায় অ্যারেলিস্টের পরিবর্তে তালিকাটিকে পছন্দ করি: আর্গুমেন্টক্যাপ্টর <তালিকা <সোমেট টাইপ>> ক্যাপ্টর;
মিগুয়েল আর সান্তেলা

146

হ্যাঁ, এটি সাধারণ জেনেরিক সমস্যা, মকিতো-নির্দিষ্ট নয়।

এর জন্য কোনও শ্রেণীর অবজেক্ট নেই ArrayList<SomeType>এবং সুতরাং আপনি কোনও প্রয়োজনীয়তার কোনও পদ্ধতিতে নিরাপদে এই জাতীয় বস্তুটি নিরাপদে টাইপ করতে পারবেন না Class<ArrayList<SomeType>>

আপনি সঠিক ধরণে বস্তুটি ফেলে দিতে পারেন:

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

এটি অনিরাপদ জঞ্জাল সম্পর্কে কিছু সতর্কতা দেবে, এবং অবশ্যই আপনার আরগমেন্টক্যাপ্টর সত্যই ArrayList<SomeType>এবং এর মধ্যে পার্থক্য করতে পারে নাArrayList<AnotherType> হয়তো উপাদান পরিদর্শন ছাড়াই।

(অন্য উত্তরে যেমন উল্লেখ করা হয়েছে, যদিও এটি সাধারণ জেনেরিক সমস্যা, তবে @Captorটীকা সহ ধরণের সুরক্ষা সমস্যার জন্য মকিতো-নির্দিষ্ট সমাধান রয়েছে It এটি এখনও একটি ArrayList<SomeType>এবং একটি মধ্যে পার্থক্য করতে পারে না ArrayList<OtherType>))

সম্পাদনা:

এছাড়াও কটাক্ষপাত tenshi এর মন্তব্যে। আপনি পাওলো ইবারম্যান থেকে মূল কোডটি এটিতে পরিবর্তন করতে পারেন (অনেক সহজ)

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

49
আপনি যে উদাহরণটি দেখিয়েছেন তা সরল করা যেতে পারে, এই ভিত্তিতে যে জাভা স্থির পদ্ধতি কলগুলির জন্য প্রকারভেদ তৈরি করে:ArgumentCaptor<List<SimeType>> argument = ArgumentCaptor.forClass((Class) List.class);
টেনশি

4
ব্যবহারগুলি চেক করা বা অনিরাপদ অপারেশন সতর্কতাগুলি অক্ষম করতে , @SuppressWarnings("unchecked")আর্গুমেন্ট ক্যাপ্টর সংজ্ঞা লাইনের উপরে টিকাটি ব্যবহার করুন । এছাড়াও, Classcastালাই অনর্থক।
শ্রীযুক্ত

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
সতর্কতা অক্ষম করার ঘোষণার আগে আপনি @ সাপ্রেস ওয়ার্নিংস ("কাঁচা টাইপস") যুক্ত করতে পারেন।
pkalinow

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

@ টেনশি এবং @ পাকালিনোর মন্তব্যের ভিত্তিতে (@rogerdpack এর কাছেও কুদো) নীচে, একটি তালিকা আর্গুমেন্ট ক্যাপ্টর তৈরির জন্য একটি সহজ সমাধান যা "চেক করা বা অনিরাপদ অপারেশনগুলি ব্যবহার করে" সতর্কতাটিকে অক্ষম করে :

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

এখানে সম্পূর্ণ উদাহরণ এবং সংশ্লিষ্ট পাসিং সিআই বিল্ড এবং পরীক্ষা এখানে চালানো

আমাদের দলটি আমাদের ইউনিট পরীক্ষাগুলিতে কিছু সময়ের জন্য এটি ব্যবহার করে আসছে এবং এটি আমাদের জন্য সবচেয়ে সহজ সমাধান বলে মনে হচ্ছে।


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>>>>() {
    }
);

এটি কাজ করে, কারণ মকিতোকে আসলে কোনও ধরণের তথ্যের প্রয়োজন হয় না (উদাহরণস্বরূপ সিরিয়ালাইজারগুলির বিপরীতে)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.