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

测试中使用ConfigurationProperties触发空指针异常问题求助

为啥测试会空指针?怎么修?

嘿,我一眼就看出问题出在哪了——你的测试里ApplicationProperties根本没被正确初始化!

你用@Autowired注入它,但如果测试类没加载Spring上下文(比如没加@SpringBootTest),这个对象就是null;就算加载了上下文,要是配置文件里没填application.bebusiness.end-point-provider,调用getBebusiness()返回的也是null,最后调用getEndPointProvider()的时候自然就触发空指针了。而你换成具体URL后,跳过了对ApplicationProperties的调用,当然就不会碰到这个问题啦。

下面给你几个实用的修复方案,按需选就行:

方案1:用Mockito模拟配置对象(推荐单元测试用)

纯Mockito模拟依赖,不用加载Spring上下文,速度快还能隔离外部影响:

public class ProviderServiceTest {
    // 把ApplicationProperties和它内部的Bebusiness都mock掉
    @Mock
    private ApplicationProperties applicationProperties;
    @Mock
    private ApplicationProperties.Bebusiness bebusinessMock; // 假设你的内部类叫Bebusiness
    @Mock
    private RestTemplate restTemplate;
    
    @InjectMocks
    private ProviderServiceImpl providerService;
    
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Test
    public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
        // 先给mock对象设好返回值
        String testUrl = "http://mock-bebusiness-url/api/providers";
        when(applicationProperties.getBebusiness()).thenReturn(bebusinessMock);
        when(bebusinessMock.getEndPointProvider()).thenReturn(testUrl);
        
        // 再模拟RestTemplate的返回
        String provider = providerInit.buildProviderDTOWithIdFromBebusiness();
        ResponseEntity<String> responseEntity = new ResponseEntity<>(provider, HttpStatus.OK);
        when(restTemplate.getForEntity(
                anyString(), 
                ArgumentMatchers.any(Class.class)
        )).thenReturn(responseEntity);
        
        // 执行测试
        List<ProviderDTO> result = providerService.getAllProviderFromBebusiness();
        
        // 断言结果,还可以顺便验证RestTemplate的调用参数对不对
        assertEquals(HttpStatus.OK.value(), responseEntity.getStatusCodeValue());
        verify(restTemplate).getForEntity(
                eq(testUrl + "&amp;page=0&amp;size=" + Integer.MAX_VALUE), 
                eq(String.class)
        );
    }
}

方案2:加载Spring上下文用真实配置(适合集成测试)

如果需要验证配置是否正确加载,可以加@SpringBootTest让Spring帮你读配置文件:

@SpringBootTest // 加载Spring上下文,读取application.properties/yaml里的配置
public class ProviderServiceTest {
    @Autowired
    private ApplicationProperties applicationProperties;
    
    @MockBean // 替换容器里的RestTemplate为mock对象
    private RestTemplate restTemplate;
    
    @Autowired
    private ProviderServiceImpl providerService;

    @Test
    public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
        // 模拟RestTemplate返回
        String provider = providerInit.buildProviderDTOWithIdFromBebusiness();
        ResponseEntity<String> responseEntity = new ResponseEntity<>(provider, HttpStatus.OK);
        when(restTemplate.getForEntity(
                anyString(), 
                ArgumentMatchers.any(Class.class)
        )).thenReturn(responseEntity);
        
        List<ProviderDTO> result = providerService.getAllProviderFromBebusiness();
        
        assertEquals(HttpStatus.OK.value(), responseEntity.getStatusCodeValue());
    }
}

这种方式会加载完整Spring上下文,测试速度会慢一点,适合需要验证配置和服务集成的场景。

方案3:手动初始化配置对象

不想用Mockito的话,也可以手动创建并初始化ApplicationProperties:

public class ProviderServiceTest {
    private ApplicationProperties applicationProperties;
    @Mock
    private RestTemplate restTemplate;
    
    private ProviderServiceImpl providerService;
    
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Before
    public void setUp() {
        // 手动创建配置对象和内部的Bebusiness实例
        applicationProperties = new ApplicationProperties();
        ApplicationProperties.Bebusiness bebusiness = new ApplicationProperties.Bebusiness();
        bebusiness.setEndPointProvider("http://test-url/api/providers");
        applicationProperties.setBebusiness(bebusiness);
        
        // 直接构造服务对象,把依赖传进去
        providerService = new ProviderServiceImpl(applicationProperties, restTemplate);
    }

    @Test
    public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
        // 模拟RestTemplate返回
        String provider = providerInit.buildProviderDTOWithIdFromBebusiness();
        ResponseEntity<String> responseEntity = new ResponseEntity<>(provider, HttpStatus.OK);
        when(restTemplate.getForEntity(anyString(), ArgumentMatchers.any(Class.class)))
                .thenReturn(responseEntity);
        
        List<ProviderDTO> result = providerService.getAllProviderFromBebusiness();
        
        assertEquals(HttpStatus.OK.value(), responseEntity.getStatusCodeValue());
    }
}
最后提醒下

别忘了你的ApplicationProperties内部的Bebusiness类得有对应的getter和setter方法,不然不管是Spring注入还是手动初始化都没法给它赋值哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:07:23