如何使用mockito验证使用此参数或其他参数调用了特定方法?

xdyibdwo  于 9个月前  发布在  其他
关注(0)|答案(2)|浏览(99)

如何使用mockito的verify方法验证我的sendMessage方法是用Msg.保存还是用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.保存);:这是我将测试是否在create情况下使用Msg.保存参数或在update情况下使用Msg.UPDATE参数调用sendMessage方法的地方。

这个检查怎么做?

lsmepo6l

lsmepo6l1#

@knittl是正确的。您的验证呼叫正确。问题是你在嘲笑你要测试的类。当你调用mock(CustomerService.class)时,Mockito实际上是在创建一个类,这个类会存根所有的方法(即覆盖它们并返回默认值):

class CustomerServiceMock extends CustomerService {
  ...
  @Override
  public Customer saveCustomer(Customer savedCustomer) {
    // Stub
    return null;
  }
  ...
}

所以customerService.saveCustomer(customer)将返回null,因为customerService实际上是一个CustomerServiceMock。assertEquals(result, customer)将因此失败。解决方案是将customerService = mock(CustomerService.class);替换为customerService = new CustomerService(customerRepository, messageInTopic)。注意,customerRepository和messageInTopic是您声明的模拟。
但是,由于这些行,您的assertEqual仍然会失败。

when(customerRepository.findCustomerByEmail(customer.getEmail())
        .thenReturn(Optional.of(customerEntity));
when(customerRepository.save(customerEntity)).thenReturn(customerEntity);

这使得saveCustomer(customer)返回mock customerEntity

  1. assertEquals失败,因为customerEntity不匹配customer
  2. 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返回customer,以便assertEqual通过。它还将使savedCustomer.getId()result.getId()相等。findCustomerByEmail无论如何都应该返回真实的客户,所以这对我来说最有意义。
另外,作为FYI: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调用的。更新消息,你不关心id。问题是你不能混合匹配器和直接参数,所以这不起作用:

verify(messageInTopic, times(1)).sendMessage(Matchers.any(), Msg.SAVE);

但这会起作用:

verify(messageInTopic, times(1)).sendMessage(Matchers.any(), Matchers.eq(Msg.SAVE));

另外,作为第二个FYI,有许多不同的方法来验证参数。这里有一个关于所有不同方式的信息的帖子:Mockito. Verify method arguments。如果你想验证是对象的参数,这一点尤其重要。

6vl6ewon

6vl6ewon2#

有几种方法可以做到这一点。例如,使用captors:
首先在测试类中声明一个要检查的参数的捕获器:

@Captor
private ArgumentCaptor<Msg.class> msgCaptor;

然后在测试中,验证并Assert正确的值:

verify(messageInTopic).sendMessage(result.getId(), msgCaptor.capture());
// If using org.assertj.core.api.Assertions.assertThat;
assertThat(msgCaptor.getValue()).isEqualTo(Msg.SAVE);

相关问题