简体   繁体   English

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

[英]Mockito ArgumentCaptor needs stubbing even I use verify

I am trying to write a Unit Test for the following service method:我正在尝试为以下服务方法编写单元测试:

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

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

I use ArgumentCaptor so that I catch the quantity parameter in the private method that my service method calls: 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...
}

The test is working, but if I remove when(quantityRepository.save(any())).thenReturn(quantity);测试正在运行,但如果我删除when(quantityRepository.save(any())).thenReturn(quantity); line, it throws "null pointer exception error" because in this case updated parameter in the update method is null.行,它抛出“空指针异常错误”,因为在这种情况下更新方法中的updated参数是 null。 So, do I have to use the mentioned stubbing in the when() method?那么,我是否必须在when()方法中使用提到的存根? I think I do not need and the verify already perform that task via verify(quantityRepository).save(quantityCaptor.capture()) .我认为我不需要,并且验证已经通过verify(quantityRepository).save(quantityCaptor.capture())执行了该任务。 Is that true?真的吗?

The problem lies in the following lines:问题在于以下几行:

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

Which is essentially the same as:这与以下内容基本相同:

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

The stubbing is necessary, because you're expecting the save method to return something, when you call updated.getUuid() .存根是必要的,因为当您调用updated.getUuid()时,您希望save方法返回一些东西。 Without the stub, updated is null and your call results in a NullPointerException .如果没有存根, updated的是 null 并且您的调用会导致NullPointerException

No, you need the stubbing here.不,你需要这里的存根。 You can't delete the when(save) call because your test depends on what return value you have for save .您无法删除when(save)调用,因为您的测试取决于您对save的返回值。 However, you're on the right track to question whether any given thing needs to be both stubbed and verified.然而,你在质疑任何给定的东西是否需要存根和验证的问题上是正确的。


You're right that it's often redundant to verify things that you've stubbed, and the docs to verify tell you so :你是对的,验证你存根的东西通常是多余的,验证verify文档告诉你

Although it is possible to verify a stubbed invocation, usually it's just redundant .尽管可以验证存根调用,但通常它只是多余的 Let's say you've stubbed foo.bar() .假设您已存根foo.bar() If your code cares what foo.bar() returns then something else breaks(often before even verify() gets executed).如果您的代码关心foo.bar()返回的内容,则其他内容会中断(通常甚至在执行verify()之前)。 If your code doesn't care what foo.bar() returns then it should not be stubbed.如果您的代码不关心foo.bar()返回的内容,则不应将其存根。

And as attributed to Aaron Jensen, quoted in " Asking and Telling " by Mockito's original author Szczepan Faber:正如 Mockito 的原作者 Szczepan Faber 在“ Asking and Telling ”中引用的 Aaron Jensen 所说:

If you're verifying you don't need to stub unless of course that method returns something that is critical to the flow of your test (or code), in which case you don't really need to verify, because the flow would have verified.如果您正在验证您不需要存根,除非该方法当然返回对您的测试(或代码)流程至关重要的东西,在这种情况下您实际上不需要验证,因为流程会已验证。

In general, if you've stubbed something, then you make your test assertions at the end and you don't need to test that the method was called—the assertions would fail.通常,如果您对某些东西进行了存根处理,那么您在最后进行测试断言,并且您不需要测试该方法是否被调用——断言会失败。 And if you verify that a method was called but nobody cares about the result—or the result is passed directly back to the caller—then you might not need to stub, because Mockito's default return values like 0 and null should work fine.如果你验证一个方法被调用但没有人关心结果——或者结果直接传回给调用者——那么你可能不需要存根,因为 Mockito 的默认返回值如0null应该可以正常工作。

Here, neither of those are true: A default null value causes an NPE, and you need to verify because that's the only supported way to get a value out of your ArgumentCaptor.在这里,这些都不正确:默认的null值会导致 NPE,您需要进行verify ,因为这是从 ArgumentCaptor 中获取值的唯一受支持的方法。 This means that you call verify , but not for the sake of actual verification, but rather to get the value out of ArgumentCaptor.这意味着您调用verify ,但不是为了实际验证,而是从 ArgumentCaptor 中获取值。 Part of the verify call is redundant, but there isn't another practical way to get to the necessary ArgumentCaptor part, so your code is fine with both when and verify . verify调用的一部分是多余的,但是没有另一种实用的方法可以到达必要的 ArgumentCaptor 部分,因此您的代码在whenverify都很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM