You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JUnit5环境下如何使用Mockito模拟被测类中的无返回值(Void)方法

Mocking Void Methods with Mockito for Your Customer Service Implementation

Let's break down how to handle void method mocking in Mockito, especially tailored to your customer service code.

First, you’re already on the right track with doNothing()—this is the standard way to suppress the real implementation of a void method when using a @Spy (since spies default to executing real code unless explicitly told otherwise). Let’s cover all relevant options and validate your current test setup.

1. Basic: Suppress Real Void Method Execution

doNothing() is perfect for your test case where you want to verify deleteCustomer is called without running the actual deletion logic (which would trigger downstream service calls like entityViewService.unassignCustomerEntityViews). Your current code for this is correct:

doNothing()
    .when(customerService)
    .deleteCustomer(any(), any());

2. Verify Calls & Capture Arguments

Your use of ArgumentCaptor to validate the CustomerId passed to deleteCustomer is a great practice. Let’s confirm this setup works as intended:

  • You capture the argument with:
    ArgumentCaptor<CustomerId> customerIdArgumentCaptor = ArgumentCaptor.forClass(CustomerId.class);
    
  • Then verify the method was called once and validate the captured argument:
    then(customerService)
        .should(times(1))
        .deleteCustomer(any(TenantId.class), customerIdArgumentCaptor.capture());
    assertEquals(CUSTOMER_ID, customerIdArgumentCaptor.getValue());
    

This correctly checks that the expected CustomerId is passed when deleteCustomersByTenantId runs.

3. Advanced: Custom Logic for Void Methods

If you need more than just suppressing the method (e.g., log parameters, modify input objects, or trigger side effects), use doAnswer() even for void methods. For example:

doAnswer(invocation -> {
    // Extract arguments passed to deleteCustomer
    TenantId tenantId = invocation.getArgument(0);
    CustomerId customerId = invocation.getArgument(1);
    
    // Add custom logic here
    System.out.printf("Delete requested for tenant %s and customer %s%n", tenantId, customerId);
    
    // Void methods require returning null
    return null;
})
.when(customerService)
.deleteCustomer(any(TenantId.class), any(CustomerId.class));

4. Simulate Exceptions from Void Methods

To test error handling (e.g., how your code reacts when deleteCustomer throws a ThingsboardException), use doThrow():

doThrow(new ThingsboardException("Test exception"))
    .when(customerService)
    .deleteCustomer(any(TenantId.class), any(CustomerId.class));

Why Your Current Setup Works

In your code, the internal customersByTenantRemover calls deleteCustomer for each found customer. Using doNothing() on your spy'd customerService prevents the real deleteCustomer logic from executing, keeping your test focused on verifying the flow of deleteCustomersByTenantId rather than downstream deletion steps.

Your test already correctly validates:

  • customerDao.findCustomersByTenantId is called once
  • deleteCustomer is called once with the expected CustomerId

This is a solid, focused test setup for your use case.

内容的提问来源于stack exchange,提问作者sobhan nami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 19:07:32