如何使用mockito捕获特定类型的列表

And*_*rle 275 java junit unit-testing mockito

有没有办法使用mockitos ArgumentCaptore捕获特定类型的列表.这不起作用:

ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(ArrayList.class);
Run Code Online (Sandbox Code Playgroud)

cru*_*dog 491

使用@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()));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我更喜欢在`@ Before`方法中使用`MockitoAnnotations.initMocks(this)`而不是使用不包括使用其他跑步者的跑步者.但是,+1,感谢指出注释. (68认同)
  • 不确定这个例子是否完整.我得到......错误:(240,40)java:变量captor可能没有被初始化我喜欢tenshi的答案如下 (4认同)
  • `initMocks(this)` 应该替换为 `openMocks(this)`,因为第一个已被弃用 (4认同)
  • 我通常更喜欢在 Captor 声明中使用 List 而不是 ArrayList: ArgumentCaptor&lt;List&lt;SomeType&gt;&gt; captor; (3认同)

Paŭ*_*ann 133

是的,这是一个普遍的泛型问题,而不是特定于mockito的问题.

没有类对象ArrayList<SomeType>,因此您无法将此类对象类型安全地传递给需要的方法Class<ArrayList<SomeType>>.

您可以将对象强制转换为正确的类型:

Class<ArrayList<SomeType>> listClass =
              (Class<ArrayList<SomeType>>)(Class)ArrayList.class;
ArgumentCaptor<ArrayList<SomeType>> argument = ArgumentCaptor.forClass(listClass);
Run Code Online (Sandbox Code Playgroud)

这将给出一些关于不安全的强制转换的警告,当然你的ArgumentCaptor无法区分ArrayList<SomeType>ArrayList<AnotherType>不检查元素.

(正如在另一个答案中所提到的,虽然这是一个普遍的泛型问题,但是对于带有@Captor注释的类型安全问题,存在Mockito特定的解决方案.它仍然无法区分an ArrayList<SomeType>和an ArrayList<OtherType>.)

编辑:

另请参阅tenshi的评论.您可以将原始代码从PaŭloEbermann更改为此(更简单)

final ArgumentCaptor<List<SomeType>> listCaptor
        = ArgumentCaptor.forClass((Class) List.class);
Run Code Online (Sandbox Code Playgroud)

  • 基于java为静态方法调用进行类型推断的事实,您展示的示例可以简化:`ArgumentCaptor <List <SimeType >> argument = ArgumentCaptor.forClass((Class)List.class);` (48认同)
  • 要禁用_uses unchecked或unsafe operations_ warning,请在参数captor定义行上方使用`@SuppressWarnings("unchecked")`注释.而且,转换为"Class"是多余的. (3认同)
  • 在我的测试中,转换为 Class 并不是多余的。 (2认同)

rog*_*ack 14

如果你不害怕旧的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.
Run Code Online (Sandbox Code Playgroud)

  • 您可以在声明之前添加@SuppressWarnings(“ rawtypes”)以禁用警告。 (2认同)

kkm*_*999 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"));
Run Code Online (Sandbox Code Playgroud)


mrt*_*rts 5

根据@tenshi 和@pkalinow 的评论(也对@rogerdpack 表示敬意),以下是创建列表参数捕获器的简单解决方案,该解决方案还禁用了“使用未经检查或不安全的操作”警告:

@SuppressWarnings("unchecked")
final ArgumentCaptor<List<SomeType>> someTypeListArgumentCaptor =
    ArgumentCaptor.forClass(List.class);
Run Code Online (Sandbox Code Playgroud)

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

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