即使我使用验证,Mockito ArgumentCaptor 也需要存根?

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

我正在尝试为以下服务方法编写单元测试:

public CommandDTO update(UUID uuid, QuantityRequest request) {
        Quantity quantity = quantityRepository.findByUuid(uuid)
                        .orElseThrow(() -> new EntityNotFoundException(QUANTITY));
        Quantity updated = saveQuantity(quantity, request);
        return CommandDTO.builder().uuid(updated.getUuid()).build();
}

private Quantity saveQuantity(Quantity quantity, QuantityRequest request) {
        //map fields (code omitted for brevity)
        return quantityRepository.save(quantity);
}

我使用

ArgumentCaptor
,以便捕获我的服务方法调用的私有方法中的
quantity
参数:
quantityRepository.save(quantity)

@Test
public void test() {
    Quantity quantity = new Quantity();

    QuantityRequest request = new QuantityRequest();
    request.setQuantity(100);

    when(quantityRepository.findByUuid(uuid)).thenReturn(Optional.of(quantity));

    // It seems to be meaningless this stubbing. because I already stb it in verify method below
    when(quantityRepository.save(any())).thenReturn(quantity);

    quantityService.update(uuid, request);

    verify(quantityRepository).save(quantityCaptor.capture());
    Quantity captured = quantityCaptor.getValue();

    // assertions...
}

测试正在工作,但是如果我删除

when(quantityRepository.save(any())).thenReturn(quantity);
行,它会抛出“空指针异常错误”,因为在这种情况下,更新方法中的
updated
参数为空。那么,我是否必须在
when()
方法中使用提到的存根?我认为我不需要它,因为验证已经通过
verify(quantityRepository).save(quantityCaptor.capture())
执行该任务。这是真的吗?

java unit-testing testing junit mockito
2个回答
1
投票

不,你需要这里的存根。您无法删除

when(save)
调用,因为您的测试取决于
save
的返回值。但是,您质疑是否需要对任何给定的事物进行存根和验证,这是正确的。


你是对的,验证你存根的东西通常是多余的,文档

verify
告诉你这一点

虽然可以验证存根调用,但通常它只是多余的。假设您已存根

foo.bar()
。如果您的代码关心
foo.bar()
返回什么,那么其他东西就会中断(通常在
verify()
执行之前)。如果您的代码不关心
foo.bar()
返回什么,那么它不应该被存根。

Mockito 的原作者 Szczepan Faber 在“询问与讲述”中引用了 Aaron Jensen 的话:

如果您正在验证,则不需要存根,除非该方法返回对测试(或代码)流程至关重要的内容,在这种情况下,您实际上不需要验证,因为流程会已验证。

一般来说,如果您对某些内容进行了存根,那么您可以在最后进行测试断言,并且不需要测试该方法是否被调用 - 断言将会失败。如果您验证某个方法被调用,但没有人关心结果,或者结果直接传递回调用者,那么您可能不需要存根,因为 Mockito 的默认返回值(如

0
null
)应该可以工作很好。

在这里,这些都不是真的:默认的

null
值会导致 NPE,并且您需要
verify
因为这是从 ArgumentCaptor 中获取值的唯一受支持的方法。这意味着您调用
verify
,但不是为了实际验证,而是为了从 ArgumentCaptor 中获取值。部分
verify
调用是多余的,但没有其他实用方法可以到达必要的 ArgumentCaptor 部分,因此您的代码对于
when
verify
都很好。


0
投票

问题出在以下几行:

  Quantity updated = saveQuantity(quantity, request);
  return CommandDTO.builder().uuid(updated.getUuid()).build();

本质上与:

相同
 Quantity updated = quantityRepository.save(quantity)
 return CommandDTO.builder().uuid(updated.getUuid()).build();

存根是必要的,因为当您调用

save
时,您期望
updated.getUuid()
方法返回一些内容。 如果没有存根,
updated
为空,并且您的调用结果为
NullPointerException

© www.soinside.com 2019 - 2024. All rights reserved.