如何使用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
相关产品推荐
相关产品推荐

