如何使用 ArgumentCaptor 进行撞击?

在 Mockito 文件Javadocs中它说

建议使用 ArgumentCaptor 进行验证,但不要使用 stub。

但是我不明白为什么 ArgumentCaptor 可以用来进行撞击。有没有人可以解释一下上面的语句,并说明如何使用 ArgumentCaptor 进行存根化,或者提供一个链接,说明如何进行存根化?

158780 次浏览

假设采用下列方法进行测试:

public boolean doSomething(SomeClass arg);

Mockito 文档指出,没有应该以这种方式使用 captor:

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));

因为你可以在按摩的时候使用 matcher:

when(someObject.doSomething(eq(expected))).thenReturn(true);

但验证是另一回事。如果您的测试需要确保使用特定的参数调用这个方法,那么使用 ArgumentCaptor,它就是为这种情况设计的:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));

排队

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

会做同样的事情

when(someObject.doSomething(Matchers.any())).thenReturn(true);

因此,当存根化没有附加值时,使用 argumentCaptor.catch ()。使用 Matchers.any ()可以更好地显示实际发生的情况,从而提高可读性。 使用 argumentCaptor.catch () ,您无法读取实际匹配的参数。 与使用 any ()不同,当您有更多信息(期望参数的类)时,可以使用更具体的匹配器来改进测试。

还有一个问题: 如果在存根化时使用 argumentCaptor.catch () ,那么就不清楚在验证之后应该捕获多少值。我们希望在验证过程中捕获一个值,而不是在存根化过程中,因为在那个时候还没有要捕获的值。那么,参数捕获器在存根化过程中捕获了什么样的方法呢?它能捕捉到任何东西,因为还没有什么东西可以捕捉到。 我认为这是未定义行为,我不想用未定义行为。

假设,如果你在搜索中发现了这个问题,那么你可能想要这个:

doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));

为什么?因为像我一样,你重视时间,你不会仅仅为了单一的测试场景而实现 .equals

99% 的测试会因为模拟返回 null 而崩溃,在一个合理的设计中,你会不惜一切代价避免返回 null,使用 Optional或者搬到 Kotlin。这意味着不需要经常使用 verify,而且 ArgumentCaptor 太单调,无法编写。