6 ответов:
вложенные дженерики-проблемы можно избежать с помощью @ Captor аннотация:
@RunWith(MockitoJUnitRunner.class) public class Test{ @Mock private Service service; @Captor private ArgumentCaptor<ArrayList<SomeType>> captor; @Test public void shouldDoStuffWithListValues() { //... verify(service).doStuff(captor.capture())); } }
Да, это общая проблема дженериков, а не mockito-specific.
нет объекта класса для
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>.)Edit:
взгляните также на теншиs комментарий. Вы можете изменить исходный код Paŭlo Ebermann к этому (гораздо проще)
final ArgumentCaptor<List<SomeType>> listCaptor = ArgumentCaptor.forClass((Class) List.class);
Если вы не боитесь старой семантики java-стиля (non type safe generic), это также работает и достаточно просто:
ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class); verify(subject.method(argument.capture()); // run your code List<SomeType> list = argument.getValue(); // first captured List, etc.
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"));
основываясь на комментариях @tenshi и @pkalinow (также престижность @rogerdpack), ниже приведено простое решение для создания похитителя аргументов списка, который также отключает "использует непроверенные или небезопасные операции" предупреждение:
@SuppressWarnings("unchecked") final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor = ArgumentCaptor.forClass(List.class);полный пример здесь и соответствующее прохождение сборки CI и тестового запуска здесь.
наша команда использовала это в течение некоторого времени в наших модульных тестов, и это выглядит как самый простой решение для нас.
у меня была такая же проблема с тестированием активности в мое приложение для Android. Я использовал
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();
Comments