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

Mockito异常场景下如何断言日志方法的执行及返回值

Mockito测试远程调用失败场景:解决空指针+验证日志方法

空指针的核心原因

你的空指针大概率是Mock的RemoteCall没有正确注入到Service实例——要么Service里还是用了真实的RemoteCall对象,要么Mock对象本身就是null。

完整测试示例(附代码)

先假设你的核心类结构是这样的:

// 远程调用接口
public interface RemoteCall {
    void callAPI() throws RemoteException;
}

// 待测试的Service类
public class ApiService {
    private final RemoteCall remoteCall;

    // 推荐用构造方法注入,方便测试
    public ApiService(RemoteCall remoteCall) {
        this.remoteCall = remoteCall;
    }

    public void handleRequest() {
        try {
            remoteCall.callAPI();
        } catch (RemoteException e) {
            logMessage("远程调用失败:" + e.getMessage());
        }
    }

    // 要验证的日志方法(假设是protected)
    protected void logMessage(String content) {
        // 实际日志逻辑
    }
}

1. 正确Mock并注入RemoteCall

这里提供两种常用方式,任选其一即可:

方式1:注解式(JUnit 5 + Mockito)

用@Mock创建Mock对象,@InjectMocks自动注入到Service:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class ApiServiceTest {
    @Mock
    private RemoteCall mockRemoteCall;

    @InjectMocks
    private ApiService apiService;

    @Test
    public void handleRequest_WhenRemoteCallFails_ShouldTriggerLogMessage() throws RemoteException {
        // 步骤1:设定Mock行为——调用callAPI时抛出指定异常
        String errorMsg = "连接超时";
        doThrow(new RemoteException(errorMsg)).when(mockRemoteCall).callAPI();

        // 步骤2:调用待测试方法
        apiService.handleRequest();

        // 步骤3:验证logMessage是否被正确调用
        // 因为logMessage是protected,需要用spy包装Service来捕获调用
        ApiService spyService = spy(apiService);
        spyService.handleRequest();
        verify(spyService).logMessage("远程调用失败:" + errorMsg);
    }
}

方式2:手动构造注入(无注解)

如果不想用Mockito注解,直接手动创建Mock并传入Service构造方法:

import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;

public class ApiServiceTest {
    @Test
    public void handleRequest_WhenRemoteCallFails_ShouldTriggerLogMessage() throws RemoteException {
        // 创建Mock对象
        RemoteCall mockRemoteCall = mock(RemoteCall.class);
        // 手动注入到Service
        ApiService apiService = new ApiService(mockRemoteCall);

        // 设定Mock行为
        String errorMsg = "连接超时";
        doThrow(new RemoteException(errorMsg)).when(mockRemoteCall).callAPI();

        // 执行测试
        apiService.handleRequest();

        // 验证日志方法
        ApiService spyService = spy(apiService);
        spyService.handleRequest();
        verify(spyService).logMessage("远程调用失败:" + errorMsg);
    }
}

2. 关键注意事项

  • 注入方式要匹配:如果你的Service用Setter注入RemoteCall,要确保Setter是public的,或者手动调用Setter注入Mock;构造方法注入是最稳妥的测试友好方式。
  • protected方法的验证:如果logMessage是public,直接verify(apiService)即可;如果是protected/private,必须用spy包装Service实例才能捕获调用。
  • 杜绝真实对象:绝对不要在测试中new真实的RemoteCall实现类,否则会触发真实API调用,导致测试失败或空指针。

空指针排查 checklist

  • 打印remoteCall对象:如果输出是MockitoMock@xxx,说明Mock成功;如果是null,说明注入失败。
  • 检查Service实例化:如果Service用了Spring的@Autowired,单元测试里不要用Spring容器加载,改用@InjectMocks或手动注入Mock。
  • 异常类型匹配:确保Mock抛出的异常和Service中catch的异常类型一致,否则不会进入logMessage分支。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 17:45:28