提问人:obela06 提问时间:8/15/2023 更新时间:8/29/2023 访问量:43
如何使用mockito验证使用此参数或其他参数调用特定方法?
How to verify that a specific method was called with this parameter or another parameter using mockito?
问:
如何使用 mockito 的 verify 方法验证我的 sendMessage 方法是否使用 Msg.SAVE 或 Msg.UPDATE 调用。
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
private final SendMessageInTopic messageInTopic;
public CustomerService (CustomerRepository customerRepository, SendMessageInTopic messageInTopic)
{
this.customerRepository = customerRepository;
this.messageInTopic= messageInTopic;
}
public Customer saveCustomer(Customer savedCustomer) {
Customer customer = customerRepository
.findCustomerByEmail(savedCustomer.getEmail());
if(customer != null) {
customer.setFirstName(savedCustomer.getFirstName());
customer.setLastName(savedCustomer.getLastName());
customer.setPhoneNumber(savedCustomer.getPhoneNumber());
messageInTopic.sendMessage(savedCustomer.getId(),Msg.SAVE)
} else {
customer = new Customer();
customer.setFirstName(savedCustomer.getFirstName());
customer.setLastName(savedCustomer.getLastName());
customer.setEmail(savedCustomer.getEmail());
customer.setPhoneNumber(savedCustomer.getPhoneNumber());
messageInTopic.sendMessage(savedCustomer.getId(),Msg.Update)
}
return customerRepository.save(customer);
}
}
public class CustomerServiceTest{
private final CustomerRepository customerRepository = mock(CustomerRepository.class);
private final CustomerService customerService = mock(CustomerService.class);
private final SendMessageInTopic messageInTopic = mock(SendMessageInTopic.class);
private final CustomerMapper customerMapper = mock(CustomerMapper.class);
@Test
void whenSaveCustomerThenMsgSAVEOrUPDATE() {
// Given
final var customerId = "123456";
final var customer =
new CustomerDto(ensUserId, 'james', 'GREWAN', '32766666', '[email protected]');
final customerEntity = mock(Customer.class);
when(customerRepository.findCustomerByEmail(customer.getEmail())
.thenReturn(Optional.of(customerEntity));
when(customerRepository.save(customerEntity)).thenReturn(customerEntity);
when(customerMapper.toDto(customerEntity)).thenReturn(customer);
// When
final var result = customrService.saveCustomer(customer);
// Then
assertEquals(result, customer);
verify(messageInTopic, times(1)).sendMessage(result.getId(),Msg.SAVE);
}
}
verify(messageInTopic, times(1)).sendMessage(result.getId(),Msg.SAVE);:在这里,我将测试我是在创建情况下使用 Msg.SAVE 参数还是在更新情况下使用 Msg.UPDATE 参数调用我的 sendMessage 方法。
请问如何做这个测试?
答:
@knittl说得对。您的验证调用是否正确。问题是你在嘲笑你试图测试的类。当您调用 时,Mockito 实际上是在创建一个存根所有方法的类(即覆盖它们并返回默认值):mock(CustomerService.class)
class CustomerServiceMock extends CustomerService {
...
@Override
public Customer saveCustomer(Customer savedCustomer) {
// Stub
return null;
}
...
}
所以将返回 null,因为 customerService 实际上是一个 CustomerServiceMock。 会因此而失败。解决方法是将 替换为 .请注意,customerRepository 和 messageInTopic 是您声明的模拟。customerService.saveCustomer(customer)
assertEquals(result, customer)
customerService = mock(CustomerService.class);
customerService = new CustomerService(customerRepository, messageInTopic)
但是,由于这些行,您的 assertEqual 仍然应该失败。
when(customerRepository.findCustomerByEmail(customer.getEmail())
.thenReturn(Optional.of(customerEntity));
when(customerRepository.save(customerEntity)).thenReturn(customerEntity);
这些使得返回 mock .saveCustomer(customer)
customerEntity
- 失败,因为不匹配。
assertEquals
customerEntity
customer
- 也不起作用,因为它等价于 .这是因为 是一个 ,这意味着它看起来像这样:
verify(messageInTopic ...
sendMessage(result.getId(),Msg.SAVE)
sendMessage(null, Msg.SAVE)
customerEntity
mock(Customer.class)
customerEntity.getId
class CustomerMock extends Customer {
...
public String getId() {
// Stub
return null;
}
...
}
有很多方法可以解决这个问题。我的建议是像这样删除和使用:customerEntity
customer
when(customerRepository.findCustomerByEmail(customer.getEmail())
.thenReturn(Optional.of(customer));
when(customerRepository.save(customer)).thenReturn(customer);
这将使 saveCustomer 返回,以便 assertEqual 通过。它也会使它变得平等。 无论如何都应该返回真正的客户,所以这对我来说最有意义。customer
savedCustomer.getId()
result.getId()
findCustomerByEmail
此外,仅供参考:Matchers.eq 和直接使用参数在功能上是相同的,因此它不会更改任何内容:
verify(messageInTopic, times(1)).sendMessage(result.getId(),Msg.SAVE);
verify(messageInTopic, times(1)).sendMessage(Matchers.eq(result.getId()), Matchers.eq(Msg.SAVE));
那么为什么要使用 Matchers.eq 呢?好吧,假设您只想验证 sendMessage 是否使用 Msg.SAVE 与 Msg.UPDATE 调用,并且您不关心 id。问题是你不能混合匹配器和直接参数,所以这不起作用:
verify(messageInTopic, times(1)).sendMessage(Matchers.any(), Msg.SAVE);
但这会起作用:
verify(messageInTopic, times(1)).sendMessage(Matchers.any(), Matchers.eq(Msg.SAVE));
此外,作为第二个参考,有许多不同的方法可以验证参数。这是一篇关于所有不同方式的信息的帖子:Mockito。验证方法参数。如果要验证作为对象的参数,这一点尤其重要。
有几种方法可以做到这一点。例如,使用捕获器:
首先在测试类中声明要检查的参数的捕获器:
@Captor
private ArgumentCaptor<Msg.class> msgCaptor;
然后在测试中,验证并断言正确的值:
verify(messageInTopic).sendMessage(result.getId(), msgCaptor.capture());
// If using org.assertj.core.api.Assertions.assertThat;
assertThat(msgCaptor.getValue()).isEqualTo(Msg.SAVE);
评论
Matchers.eq
CustomerService.saveCustomer
sendMessage