如何使用ArgumentCaptor进行存根?

问题描述 投票:0回答:4

在 Mockito documentationjavadocs 中它说

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

但我不明白如何使用 ArgumentCaptor 进行存根。有人可以解释上面的语句并展示如何使用 ArgumentCaptor 进行存根或提供一个链接来展示如何完成它吗?

java unit-testing junit mockito
4个回答
285
投票

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

public boolean doSomething(SomeClass arg);

Mockito 文档说你不应该以这种方式使用 captor:

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

因为你可以在存根期间使用匹配器:

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));
    

4
投票
假设,如果搜索让您找到这个问题,那么您可能想要这个:

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

为什么?因为像我一样,您重视时间,并且您不会仅仅为了单个测试场景而实施

.equals

99% 的测试都会失败,从 Mock 返回 null,在合理的设计中,您将不惜一切代价避免返回

null

,使用 
Optional
 或迁移到 Kotlin。这意味着 
verify
 不需要经常使用,而且 ArgumentCaptor 编写起来太乏味了。


0
投票
线路

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
会做同样的事情

when(someObject.doSomething(Matchers.any())).thenReturn(true);
因此,当存根没有附加值时使用 argumentCaptor.capture() 。使用 Matchers.any() 可以更好地显示实际发生的情况,因此可读性更好。
使用 argumentCaptor.capture(),您无法读取哪些参数真正匹配。
当您有更多信息(预期参数的类)时,您可以使用更具体的匹配器,而不是使用 any() 来改进您的测试。

还有一个问题: 如果在存根时使用 argumentCaptor.capture() ,那么验证后您应该期望捕获多少个值就变得不清楚了。我们希望在验证期间捕获一个值,而不是在存根期间捕获,因为此时还没有可以捕获的值。那么参数捕获器捕获方法在存根期间捕获什么?它捕获任何东西,因为还没有任何东西可以捕获。 我认为这是未定义的行为,我不想使用未定义的行为。


0
投票
除了(正确)指出为什么通常不推荐它的答案之外,有时它正是您想要的。

假设您想要模拟一个存储库,该存储库接受客户对象并返回它,但设置了一些自动生成的字段(id、createdAt、updatedAt)。在这种情况下,您想要返回给定的相同对象,为此您需要捕获器。

这是可能的,但你必须使用 lambda 语法:

var captor = ArgumentCaptor.forClass(Customer.class); when(repo.save(captor.capture())).thenAnswer(invocation -> captor.getValue() .withId(1) .withCreatedAt(now()) .withUpdatedAt(now()));
    
© www.soinside.com 2019 - 2024. All rights reserved.