【问题标题】:Mocking a void method in the same class that is under test with mockito and junit5?在使用mockito和junit5测试的同一类中模拟一个void方法?
【发布时间】:2021-10-19 14:38:09
【问题描述】:

我想在使用 mockito 测试的同一个类中模拟一个 void 方法。 我可以用 @Spy 注释测试类,然后使用下面的代码返回我想要的数据。

        willAnswer(arg -> arg.getArgument(0))
            .given(customerService)
            .saveCustomer(any(Customer.class));

但是如何为 void 方法做到这一点。 (我已经尝试过 willDoNothing().given() 函数)

这是我真正的方法:

public void deleteCustomersByTenantId(TenantId tenantId) throws ThingsboardException {
    log.trace("Executing deleteCustomersByTenantId, tenantId [{}]", tenantId);
    Validator.validateId(tenantId, "Incorrect tenantId " + tenantId);
    customersByTenantRemover.removeEntities(tenantId, tenantId);
}

public void deleteCustomer(TenantId tenantId, CustomerId customerId) throws ThingsboardException {
    log.trace("Executing deleteCustomer [{}]", customerId);
    Validator.validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
    Customer customer = findCustomerById(tenantId, customerId);
    if (customer == null) {
        throw new IncorrectParameterException("Unable to delete non-existent customer.");
    }
    entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId);
    assetService.unassignCustomerAssets(customer.getTenantId(), customerId);
    userService.deleteCustomerUsers(customer.getTenantId(), customerId);
    deleteEntityRelations(tenantId, customerId);
    entityGroupDao.deleteEntityGroupsByTenantIdAndCustomerId(customer.getTenantId(), customerId);
    customerDao.removeById(tenantId, customerId.getId());
}

private final PaginatedRemover<TenantId, Customer> customersByTenantRemover =
        new PaginatedRemover<>() {

            @Override
            protected PageData<Customer> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
                return customerDao.findCustomersByTenantId(id.getId(), pageLink);
            }

            @Override
            protected void removeEntity(TenantId tenantId, Customer entity) throws ThingsboardException {
                deleteCustomer(tenantId, new CustomerId(entity.getUuidId()));
            }
        };

这是测试:

void deleteCustomersByTenantId() throws ThingsboardException {
    //given
    Customer customer = new Customer();
    customer.setId(CUSTOMER_ID);
    customer.setTenantId(TENANT_ID);

    ArgumentCaptor<CustomerId> customerIdArgumentCaptor = ArgumentCaptor.forClass(CustomerId.class);

    var pageData = new PageData<>(Collections.singletonList(customer), 1 ,1 , false);

    given(customerDao.findCustomersByTenantId(any(UUID.class), any(PageLink.class)))
            .willReturn(pageData);
    doNothing()
            .when(customerService)
            .deleteCustomer(any(), any());

    //when
    customerService.deleteCustomersByTenantId(TENANT_ID);

    //then
    then(customerDao)
            .should(times(1))
            .findCustomersByTenantId(any(UUID.class), any(PageLink.class));
    then(customerService)
            .should(times(1))
            .deleteCustomer(any(TenantId.class), customerIdArgumentCaptor.capture());
    assertEquals(CUSTOMER_ID, customerIdArgumentCaptor.getValue());
}

这是模拟:

//other mocks...

@Mock
private RelationService relationService;

@Mock
private CustomerValidator customerValidator;

@InjectMocks
@Spy
private CustomerServiceImpl customerService;

每个依赖项都是用@Mock 模拟的。

【问题讨论】:

  • 你在测试前做过 MockitoAnnotations.initMocks() 吗?
  • 是的,我在依赖项上使用注释模拟,在被测类上使用 InjectMock 和 Spy

标签: java spring mockito junit5


【解决方案1】:

什么都不做对我有用。请注意调用顺序

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

doNothing().when(yourMock).yourMethod(yourArgs);

这个thread 处理了一个类似的问题,使用间​​谍来模拟具有静态工厂的特定方法应该可以工作。我见过有人做反向操作(在某些特定情况下使用 Mock 然后调用真实方法),但从未亲自尝试过..

【讨论】:

  • 这个我用过,但是和另一个一样,它调用了类中的真实方法。
  • 检查传递的参数是否与您在模拟参数中提供的完全匹配。要问自己的一个重要问题是为什么需要从被测类本身模拟一个方法。这可能是需要隔离的代码设计气味
  • 是的,它们是一样的。我什至将 any() 用于 args
  • 你能提供一个最小的工作示例吗?
  • 我向问题添加方法
猜你喜欢
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多