即使我使用验证,Mockito ArgumentCaptor 也需要存根
Mockito ArgumentCaptor needs stubbing even I use verify
我正在尝试为以下服务方法编写单元测试:
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())
执行了该任务。是真的吗?
问题出在以下几行:
Quantity updated = saveQuantity(quantity, request);
return CommandDTO.builder().uuid(updated.getUuid()).build();
这与以下基本相同:
Quantity updated = quantityRepository.save(quantity)
return CommandDTO.builder().uuid(updated.getUuid()).build();
存根是必要的,因为当您调用 updated.getUuid()
时,您希望 save
方法能够 return 某些东西。
没有存根,updated
为空,您的调用结果为 NullPointerException
.
不,这里需要存根。您无法删除 when(save)
调用,因为您的测试取决于 save
的 return 值。但是,您在质疑任何给定事物是否需要存根和验证方面走在正确的轨道上。
你是对的,验证你存根的东西通常是多余的,the docs to verify
tell you so:
Although it is possible to verify a stubbed invocation, usually it's just redundant. Let's say you've stubbed foo.bar()
. If your code cares what foo.bar()
returns then something else breaks(often before even verify()
gets executed). If your code doesn't care what foo.bar()
returns then it should not be stubbed.
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.
一般来说,如果您对某些内容进行了存根,那么您会在最后进行测试断言,并且您不需要测试该方法是否已被调用——断言会失败。如果你验证一个方法被调用但没有人关心结果——或者结果直接传回给调用者——那么你可能不需要存根,因为 Mockito 的默认 return 值像 0
null
应该可以正常工作。
这里,这些都不是真的:默认 null
值会导致 NPE,您需要 verify
因为这是从 ArgumentCaptor 获取值的唯一受支持方式。这意味着您调用 verify
,但不是为了实际验证,而是为了从 ArgumentCaptor 中获取值。 verify
调用的一部分是多余的,但是没有另一种实用的方法可以到达必要的 ArgumentCaptor 部分,因此您的代码适用于 when
和 verify
.
我正在尝试为以下服务方法编写单元测试:
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())
执行了该任务。是真的吗?
问题出在以下几行:
Quantity updated = saveQuantity(quantity, request);
return CommandDTO.builder().uuid(updated.getUuid()).build();
这与以下基本相同:
Quantity updated = quantityRepository.save(quantity)
return CommandDTO.builder().uuid(updated.getUuid()).build();
存根是必要的,因为当您调用 updated.getUuid()
时,您希望 save
方法能够 return 某些东西。
没有存根,updated
为空,您的调用结果为 NullPointerException
.
不,这里需要存根。您无法删除 when(save)
调用,因为您的测试取决于 save
的 return 值。但是,您在质疑任何给定事物是否需要存根和验证方面走在正确的轨道上。
你是对的,验证你存根的东西通常是多余的,the docs to verify
tell you so:
Although it is possible to verify a stubbed invocation, usually it's just redundant. Let's say you've stubbed
foo.bar()
. If your code cares whatfoo.bar()
returns then something else breaks(often before evenverify()
gets executed). If your code doesn't care whatfoo.bar()
returns then it should not be stubbed.
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.
一般来说,如果您对某些内容进行了存根,那么您会在最后进行测试断言,并且您不需要测试该方法是否已被调用——断言会失败。如果你验证一个方法被调用但没有人关心结果——或者结果直接传回给调用者——那么你可能不需要存根,因为 Mockito 的默认 return 值像 0
null
应该可以正常工作。
这里,这些都不是真的:默认 null
值会导致 NPE,您需要 verify
因为这是从 ArgumentCaptor 获取值的唯一受支持方式。这意味着您调用 verify
,但不是为了实际验证,而是为了从 ArgumentCaptor 中获取值。 verify
调用的一部分是多余的,但是没有另一种实用的方法可以到达必要的 ArgumentCaptor 部分,因此您的代码适用于 when
和 verify
.