是否有一种方法使用mockitos ArgumentCaptore捕获特定类型的列表。这行不通:

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

当前回答

基于@tenshi和@pkalinow的评论(也是对@rogerdpack的赞扬),下面是一个简单的解决方案,用于创建一个列表参数捕获器,同时禁用“使用未检查或不安全操作”警告:

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

完整的示例在这里和相应的通过CI构建和测试运行在这里。

我们的团队已经在单元测试中使用了一段时间,这看起来是我们最直接的解决方案。

其他回答

是的,这是一个一般的泛型问题,不是模拟对象特有的。

没有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>。

(正如在另一个答案中提到的,虽然这是一个一般的泛型问题,但对于@Captor注释的类型安全问题,有一个特定于mockito的解决方案。它仍然不能区分ArrayList<SomeType>和ArrayList<OtherType>。)

编辑:

再看看tenshi的评论。您可以将原始代码更改为以下简化版本:

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

嵌套泛型问题可以通过@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()));
    }
}
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"));

如果你不害怕旧的java风格(非类型安全泛型)语义,这也可以工作,而且很简单:

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

对于junit的早期版本,您可以这样做

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