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

Mockito单元测试如何Mock内部调用依赖类并自定义返回值

问题核心原因

你当前测试代码不生效的核心问题有两个:

  • 你创建的class2 mock实例没有被被测方法实际调用:现有methodToBeTested方法内部要么直接硬编码实例化class2、要么调用class2的静态方法,外部创建的mock对象根本传不进执行链路,自然不会按你预设的规则返回值。
  • 如果你调用的是class2的静态方法,普通Mockito的mock()方法无法拦截静态调用,需要用专门的静态mock能力。
标准实现方案(推荐,符合Spring Boot开发规范)

Spring Boot项目本身推荐构造器注入依赖,这种写法天然适配单元测试,不需要额外改测试逻辑,步骤如下:

  1. 改造被测类Class1,将所有依赖(包括class2以及其他你要mock的类)作为类成员,通过构造器注入,禁止在业务方法内部直接new依赖实例。
    改造后的Class1示例:
// 类名遵循Java大驼峰命名规范
@Component
public class Class1 {
    // 所有依赖作为final成员变量
    private final Class2 class2;
    // 多个依赖直接加在构造器参数里即可,比如Class3、Class4
    // private final Class3 class3;

    // 构造器注入,Spring运行时会自动注入对应实例,单测时可以手动传入mock对象
    public Class1(Class2 class2) {
        this.class2 = class2;
    }

    public Class1ReturnType methodToBeTested(/* 你的业务入参 */) {
        // 省略其他业务逻辑
        // 调用注入的class2实例的方法,不要写new Class2().method()或者Class2.method()这种硬编码
        ReturnData rd = class2.targetMethod(/* 业务入参 */);
        // 省略后续基于rd的处理逻辑
        return returnObj;
    }
}
  1. 编写单元测试时,先给mock对象定义返回规则,再注入被测类执行方法。

纯Mockito单元测试(不启动Spring容器,执行速度最快)

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;

public class Class1Test {

    @Test
    void testMethodToBeTested_SuccessScenario() {
        // 第一步:mock所有依赖
        Class2 mockClass2 = mock(Class2.class);
        // 其他依赖同理mock:Class3 mockClass3 = mock(Class3.class);

        // 第二步:按当前测试场景构造预设返回值,定义mock规则
        ReturnData presetSuccessReturn = new ReturnData();
        presetSuccessReturn.setCode(200);
        presetSuccessReturn.setMsg("success");
        // 规则:当class2的targetMethod被调用(任意入参用any()匹配,也可以指定明确入参做精确匹配),返回预设对象
        when(mockClass2.targetMethod(any())).thenReturn(presetSuccessReturn);
        // 其他依赖的返回规则按同样方式定义即可

        // 第三步:把mock对象传入被测类构造器,创建被测实例
        Class1 class1UnderTest = new Class1(mockClass2);

        // 第四步:执行被测方法
        Class1ReturnType testResult = class1UnderTest.methodToBeTested();

        // 第五步:按业务预期做断言即可
    }

    @Test
    void testMethodToBeTested_ErrorScenario() {
        // 不同测试场景只需要修改预设的返回值即可,和其他测试用例完全隔离
        Class2 mockClass2 = mock(Class2.class);
        ReturnData presetErrorReturn = new ReturnData();
        presetErrorReturn.setCode(500);
        presetErrorReturn.setMsg("internal error");
        when(mockClass2.targetMethod(any())).thenReturn(presetErrorReturn);

        Class1 class1UnderTest = new Class1(mockClass2);
        Class1ReturnType testResult = class1UnderTest.methodToBeTested();
        // 对应异常场景的断言
    }
}

Spring上下文集成测试写法

如果需要启动Spring容器做集成测试,直接用@MockBean注解自动替换容器里的真实实例为mock对象即可:

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.junit.jupiter.api.Test;
import javax.annotation.Resource;

@SpringBootTest
public class Class1IntegrationTest {

    // 自动将Spring容器中Class2类型的Bean替换为mock对象
    @MockBean
    private Class2 mockClass2;

    // 注入被测类,其依赖的Class2已经是上面的mock实例
    @Resource
    private Class1 class1UnderTest;

    @Test
    void testSuccessScenario() {
        ReturnData presetReturn = new ReturnData();
        presetReturn.setCode(200);
        when(mockClass2.targetMethod(any())).thenReturn(presetReturn);
        // 直接执行被测方法即可,不需要手动实例化Class1
        Class1ReturnType result = class1UnderTest.methodToBeTested();
        // 断言
    }
}
特殊场景处理
  • 如果暂时无法改造被测类代码,被调用的是Class2的静态方法:使用Mockito 3.4.0+版本提供的mockStatic能力即可,注意要写在try-with-resources块中自动释放mock:
try (MockedStatic<Class2> class2StaticMock = mockStatic(Class2.class)) {
    ReturnData presetReturn = new ReturnData();
    presetReturn.setCode(200);
    class2StaticMock.when(() -> Class2.targetStaticMethod(any())).thenReturn(presetReturn);
    // 块内执行被测方法,静态调用会自动返回预设值
    Class1ReturnType result = class1UnderTest.methodToBeTested();
}
  • 如果方法内有多个依赖需要mock,只需要给每个依赖分别mock实例、定义对应场景的返回规则即可,不同测试用例的mock规则互不影响。

注意:如果业务方法内部直接通过new Class2()创建依赖实例,任何mock方式都无法替换该实例,必须先改成依赖注入的写法才能正常mock。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:45:35