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

修改密码为EncryptedPassword引用类型后Java单元测试报空指针异常

问题根因

你遇到的空指针异常来自EncryptedPassword类的decrypt()方法,核心原因是手动new出来的EncryptedPassword实例不会被Spring完成依赖注入,类内标注@Autowired的passwordUtil属性为null,调用passwordUtil.convert时触发空指针。


排查步骤

  • 给单元测试加完整异常栈打印:在client.getItems()外层添加try-catch捕获异常,打印完整栈轨迹,可直接定位到异常抛出的具体代码行
  • 断点调试:在EncryptedPassword的构造方法、decrypt方法分别打断点,运行测试即可直观看到passwordUtil属性为null,直接确认问题点

解决方案

方案1:改造EncryptedPassword,放弃依赖注入

把EncryptedPassword改造成普通POJO,依赖通过参数传入即可,适合不需要Spring管理的场景:

public class EncryptedPassword {
    
    private String encryptedPass;

    public EncryptedPassword (String encryptedString) {
        encryptedPass = encryptedString;
    }

    // PasswordUtil作为参数传入方法
    public String decrypt(PasswordUtil passwordUtil) {
        return new String(passwordUtil.convert(new Base64().decode(encryptedPass)), Charsets.UTF_8);
    }
}

后续调用decrypt时,传入Spring容器中已初始化完成的PasswordUtil实例即可。

方案2:把EncryptedPassword交给Spring容器管理

如果需要保留@Autowired注入逻辑,就不要手动调用构造方法new实例,通过Spring上下文获取Bean:

  1. 给EncryptedPassword类上加@Component注解,标注为Spring管理的Bean
  2. 单元测试引入Spring Test支持,直接注入Bean使用,改造示例:
@SpringBootTest
public class MenuRestClientTest {
    private static String host;
    private static String user;
    private static String pass;

    @Autowired
    private EncryptedPassword encryptedPassword;

    @BeforeAll
    public static void setup() {
        host = "host";
        user = "user";
        pass = "test123";
    }

    @Test 
    void queryNumberOfItems() throws Exception {
        // 给EncryptedPassword补充setEncryptedPass方法后设置属性
        encryptedPassword.setEncryptedPass(pass);
        MenuRestClient client = new MenuRestClient(host).credentials(user, encryptedPassword);

        final int items = client.getItems();
        logger.info("Found {} items", items);
    }
}

方案3:单元测试Mock依赖

仅单元测试场景下可以用Mock工具绕过依赖注入问题,示例:

@Test 
void queryNumberOfItems() throws Exception {
    EncryptedPassword password = new EncryptedPassword(pass);
    // Mock PasswordUtil实例
    PasswordUtil mockUtil = Mockito.mock(PasswordUtil.class);
    Mockito.when(mockUtil.convert(Base64.decodeBase64(pass))).thenReturn("test123".getBytes(Charsets.UTF_8));
    // 反射给password注入mock的util
    ReflectionTestUtils.setField(password, "passwordUtil", mockUtil);

    MenuRestClient client = new MenuRestClient(host).credentials(user, password);
    final int items = client.getItems();
    logger.info("Found {} items", items);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:36:04