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

JUnit测试替换@RunWith为@ExtendWith后出现空指针异常

空指针异常根因

从@RunWith(MockitoJUnitRunner.class)切换到@ExtendWith(MockitoExtension.class)后出现空指针,是三个问题共同导致的:

  • JUnit版本混用不兼容:测试类继承了JUnit 3的基类junit.framework.TestCase,导入的@Test、@Test(expected = ...)是JUnit 4的注解,而@ExtendWith是JUnit 5(Jupiter)专属的扩展注解,三套测试框架的生命周期逻辑完全冲突。MockitoExtension只会在纯JUnit 5的运行环境下触发Mock初始化逻辑,混用框架时@Mock、@InjectMocks标注的字段不会被初始化,全部为null,自然触发空指针。之前用的MockitoJUnitRunner是JUnit 4专属的Runner,能兼容原有的JUnit4+JUnit3继承结构,所以之前可以正常运行。
  • Key类型的Mock对象未初始化:测试类中Key key字段的@Mock注解被注释,该字段始终为null。你仅在第一个测试方法中尝试通过反射给被测类注入不存在的key字段(被测类的key是方法内局部变量,根本没有类级别的key字段,这个反射操作本身无效),第二个测试方法完全没有处理key的null值,执行到Mockito.when(key.deriveTwiceAndDecryptLocal(...))时直接触发空指针。
  • 被测类的配置值未注入:被测类IdpsDecryptorImpl中的idpsKey是通过@Value注入的私有字段,你在测试类中定义的private String idpsKey = "testKey"是测试类自身的字段,和被测类没有关联。你MockidpsClient.newKeyHandleLatest(idpsKey)时传入的是测试类的"testKey",但被测类实际调用方法时传入的是自身未初始化的idpsKey(值为null),和Mock的参数不匹配,Mock不会生效,会返回Mockito默认的null值,后续调用keyHandle的方法时同样会触发空指针。
修复方案

按以下步骤调整测试代码即可:

  1. 统一JUnit版本为JUnit 5,删除extends TestCase的继承逻辑,将所有JUnit 4的导入替换为JUnit 5的对应类:
    • 把org.junit.Test替换为org.junit.jupiter.api.Test
    • 把org.junit.Assert替换为org.junit.jupiter.api.Assertions
    • 移除@Test(expected = StorageException.class)的写法,改用JUnit 5的assertThrows做异常断言
  2. 给Key key字段加上@Mock注解,删除无效的反射注入key字段的代码,被测类的Key实例是方法返回值,不需要反射注入。
  3. 每个测试方法执行前,通过反射给被测类注入idpsKey的测试值。
  4. 删除异常测试方法中assertNull的无效代码——方法抛出异常后后续逻辑不会执行,这段断言永远不会被触发。

修复后的测试代码参考:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

@ExtendWith(MockitoExtension.class)
public class IdpsDecryptorImplTest {

    @InjectMocks
    private IdpsDecryptorImpl idpsDecryptorimpl;

    @Mock
    Key key;

    @Mock
    IdpsClient idpsClient;

    private final String idpsKey = "testKey";

    // 每个测试执行前注入配置值
    @org.junit.jupiter.api.BeforeEach
    void setUp() {
        ReflectionTestUtils.setField(idpsDecryptorimpl, "idpsKey", idpsKey);
    }

    @Test
    public void testDecrypt() throws IdpsCommunicationException, IdpsException {
        byte[] encryptedBytes = new byte[2];
        encryptedBytes[0] = 20;
        encryptedBytes[1] = 30;

        byte[] decryptedBytes = new byte[2];
        decryptedBytes[0] = 97;
        decryptedBytes[1] = 98;

        Mockito.when(idpsClient.newKeyHandleLatest(idpsKey)).thenReturn(key);
        Mockito.when(key.deriveTwiceAndDecryptLocal(encryptedBytes)).thenReturn(decryptedBytes);

        assertNotNull(idpsDecryptorimpl.decrypt(encryptedBytes));
    }

    @Test
    public void testDecryptException() throws IdpsCommunicationException, IdpsException {
        byte[] encryptedBytes = new byte[1];
        encryptedBytes[0] = 20;

        Mockito.when(idpsClient.newKeyHandleLatest(idpsKey)).thenReturn(key);
        Mockito.when(key.deriveTwiceAndDecryptLocal(encryptedBytes)).thenThrow(new IdpsException());
        
        assertThrows(StorageException.class, () -> idpsDecryptorimpl.decrypt(encryptedBytes));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 05:36:26