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

如何使用Mockito模拟类内依赖解决JUnit测试空指针异常

空指针根因很明确:你直接用new Class2()创建被测对象时,没有依赖注入容器处理@Inject注解标记的依赖,entityMapper字段默认是null,调用它的map方法必然触发空指针。Mockito完全可以解决这个问题,两种常用实现方式如下:

方案1:注解方式(推荐,代码最简洁)

用Mockito自带的依赖注入注解自动完成mock对象注入,不需要手动写反射逻辑。

  • JUnit 5环境:直接在测试类上加@ExtendWith(MockitoExtension.class)开启Mockito注解支持,用@Mock标记要模拟的依赖,@InjectMocks标记被测类,Mockito会自动把mock出的依赖注入到被测类实例中。
    示例代码:
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.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class Class2Test {

    @Mock
    private EntityMapper entityMapper;

    @InjectMocks
    private Class2 class2;

    @Test
    public void test() throws Exception {
        Class1 class1 = new Class1(100, "TE", "TEST");
        Mapped<Class3> mockResult = new Mapped<>(new Class3());
        // 定义mock对象的调用返回规则
        when(entityMapper.map(eq(class1), eq(Class3.class))).thenReturn(mockResult);

        Mapped<Class3> result = class2.map(class1, Class3.class);
        // 后续自行添加断言逻辑即可
    }
}
  • JUnit 4环境:不需要加类上的扩展注解,在初始化方法里手动开启Mockito注解即可:
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

public class Class2Test {

    @Mock
    private EntityMapper entityMapper;

    @InjectMocks
    private Class2 class2;

    @Before
    public void initMocks() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void test() throws Exception {
        // 测试逻辑和JUnit5版本完全一致
        Class1 class1 = new Class1(100, "TE", "TEST");
        Mapped<Class3> mockResult = new Mapped<>(new Class3());
        when(entityMapper.map(eq(class1), eq(Class3.class))).thenReturn(mockResult);
        Mapped<Class3> result = class2.map(class1, Class3.class);
    }
}
方案2:手动反射注入(无注解场景适用)

如果不想用Mockito注解,可以手动mock依赖后,通过反射把mock实例写入Class2的私有字段:

import org.junit.Test;
import org.mockito.Mockito;
import java.lang.reflect.Field;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

public class Class2Test {

    @Test
    public void test() throws Exception {
        Class1 class1 = new Class1(100, "TE", "TEST");
        Class2 class2 = new Class2();
        
        // 手动创建mock对象
        EntityMapper mockMapper = Mockito.mock(EntityMapper.class);
        // 反射注入私有字段
        Field mapperField = Class2.class.getDeclaredField("entityMapper");
        mapperField.setAccessible(true);
        mapperField.set(class2, mockMapper);

        // 定义mock返回规则
        Mapped<Class3> mockResult = new Mapped<>(new Class3());
        when(mockMapper.map(eq(class1), eq(Class3.class))).thenReturn(mockResult);
        
        Mapped<Class3> result = class2.map(class1, Class3.class);
    }
}

注意点:如果定义mock行为时不关心具体入参,可以把eq()替换为any()做通用匹配;如果被测类有构造函数、setter方法优先用构造/setter注入依赖,比反射更稳妥,只有私有字段无注入入口时才用反射或者@InjectMocks。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 13:03:11