Как записать список конкретного типа с mockito
есть ли способ захватить список определенного типа с помощью Mockitos ArgumentCaptore. Это не работает:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
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-style (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();