是否有一种方法使用mockitos ArgumentCaptore捕获特定类型的列表。这行不通:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
是否有一种方法使用mockitos ArgumentCaptore捕获特定类型的列表。这行不通:
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
当前回答
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"));
其他回答
我在我的Android应用程序中测试活动也有同样的问题。我使用ActivityInstrumentationTestCase2和mockitoannotation . 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();
对于junit的早期版本,您可以这样做
Class<Map<String, String>> mapClass = (Class) Map.class;
ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(mapClass);
嵌套泛型问题可以通过@Captor注释来避免:
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()));
}
}
在Mockito的GitHub上有一个关于这个确切问题的公开问题。
我发现了一个简单的解决方法,它不会强迫你在测试中使用注释:
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());
或者使用类似Jackson的TypeReference的语法:
ArgumentCaptor<Supplier<Set<List<Object>>>> fancyCaptor = captorFor(
new CaptorTypeReference<Supplier<Set<List<Object>>>>() {
}
);
它可以工作,因为Mockito实际上不需要任何类型信息(例如,与序列化器不同)。
基于@tenshi和@pkalinow的评论(也是对@rogerdpack的赞扬),下面是一个简单的解决方案,用于创建一个列表参数捕获器,同时禁用“使用未检查或不安全操作”警告:
@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
ArgumentCaptor.forClass(List.class);
完整的示例在这里和相应的通过CI构建和测试运行在这里。
我们的团队已经在单元测试中使用了一段时间,这看起来是我们最直接的解决方案。