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

JUnit测试中TheConfiguration Mock为空引发空指针异常问题排查

问题分析与解决

问题重现

待测试的Authentication类:

@Component
@Slf4j
public class Authentication {

    private final RestTemplate restTemplate;

    @Autowired
    private TheConfiguration config;

    public Authentication(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }


    public String generateAuthentification(){

        String plainCreds = config.geUser()+":"+config.getPassword();
        byte[] plainCredsBytes = plainCreds.getBytes();
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);

        return new String(base64CredsBytes);
    }

}

JUnit测试代码:

import static org.mockito.Mockito.when;
import org.apache.commons.codec.binary.Base64;
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 org.springframework.web.client.RestTemplate;

import com.example.TheConfiguration;

@ExtendWith(MockitoExtension.class)
class AuthenticationTest {

    @InjectMocks
    Authentication authentication;

    @Mock
    RestTemplate restTemplate;

    @Mock
    TheConfiguration config;

    @Test
    void testGenerateAuthentifications() {

        when(config.getUser()).thenReturn("user");
        when(config.getPassword()).thenReturn("pass");
        String plainCreds = config.getUser() + ":" + config.getPassword();
        System.out.println(plainCreds);
        byte[] plainCredsBytes = plainCreds.getBytes();
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
        String a = new String(base64CredsBytes);

        assertEquals(authentication.generateAuthentification(),a);

    }

}

运行测试时抛出NullPointerException:

Cannot invoke "com.example.TheConfiguration.getUser()" because "this.config" is null

完整错误日志:

java.lang.NullPointerException: Cannot invoke "com.example.TheConfiguration.getUser()" because "this.config" is null
at com.example.Authentication.generateAuthentification(Authentication.java:26)
at com.example.AuthenticationTest.testGenerateAuthentifications(AuthenticationTest.java:38)
... 省略后续堆栈信息

错误原因

Mockito的@InjectMocks注入优先级为:构造函数注入 > setter方法注入 > 字段注入。你的Authentication类有一个带参数的构造函数(仅注入RestTemplate),Mockito会优先使用这个构造函数创建实例,不会自动注入@Autowired标注的config字段,导致config为null。

另外,代码里存在笔误:config.geUser()应该是config.getUser(),这也是后续需要修正的点。

解决方法

方法1:构造函数注入所有依赖(推荐,符合Spring最佳实践)

将TheConfiguration加入构造函数,移除字段上的@Autowired:

@Component
@Slf4j
public class Authentication {

    private final RestTemplate restTemplate;
    private final TheConfiguration config;

    // Spring 4.3+支持构造函数自动装配,无需@Autowired
    public Authentication(RestTemplate restTemplate, TheConfiguration config) {
        this.restTemplate = restTemplate;
        this.config = config;
    }


    public String generateAuthentification(){
        // 修正笔误:geUser -> getUser
        String plainCreds = config.getUser()+":"+config.getPassword();
        byte[] plainCredsBytes = plainCreds.getBytes();
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);

        return new String(base64CredsBytes);
    }

}

修改后,Mockito的@InjectMocks会自动通过构造函数注入两个Mock对象,测试代码无需改动。

方法2:给config添加Setter方法

如果不想修改构造函数,可以给config添加Setter方法,让Mockito通过Setter注入:

@Component
@Slf4j
public class Authentication {

    private final RestTemplate restTemplate;

    private TheConfiguration config;

    public Authentication(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Autowired
    public void setConfig(TheConfiguration config) {
        this.config = config;
    }


    public String generateAuthentification(){
        String plainCreds = config.getUser()+":"+config.getPassword(); // 修正笔误
        byte[] plainCredsBytes = plainCreds.getBytes();
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);

        return new String(base64CredsBytes);
    }

}

方法3:测试中手动注入config

在测试方法里通过反射手动给authentication的config字段赋值:

@Test
void testGenerateAuthentifications() {
    // 手动注入config
    ReflectionTestUtils.setField(authentication, "config", config);

    when(config.getUser()).thenReturn("user");
    when(config.getPassword()).thenReturn("pass");
    String plainCreds = config.getUser() + ":" + config.getPassword();
    byte[] plainCredsBytes = plainCreds.getBytes();
    byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
    String a = new String(base64CredsBytes);

    assertEquals(authentication.generateAuthentification(),a);
}

需要导入org.springframework.test.util.ReflectionTestUtils类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 00:31:03