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

Spring Boot测试时被测Service类@Value注入属性返回null

问题描述

我有一个基于Spring Boot 2.7.0版本搭建的项目,针对dev、test环境分别配置了独立的配置文件:application-dev.properties和application-test.properties,项目中未配置默认的application.properties文件。

在被测Service类中,我需要从application-test.properties文件加载指定属性值,该Service类代码如下:

@Service
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {

    @Value("${files.root-directory}")
    private String fileDirectory;

    @Override
    @Transactional(readOnly = false)
    public File createFile(CreateFileCommand command) {
        var filePath = FileUtil.getPath(fileDirectory); // 测试场景下fileDirectory为null
        // ....
    }
}

使用dev profile启动应用时所有功能运行正常,但测试场景下fileDirectory属性始终为null。

对应测试类代码如下:

@SpringBootTest
@ActiveProfiles("test")
@ExtendWith(MockitoExtension.class)
public class FileServiceTest {
    // ...
}

应用启动测试类代码如下:

@SpringBootTest
@ActiveProfiles("test")
@TestPropertySource("classpath:application-test.properties")
@EnableConfigurationProperties
class ApiApplicationTests {

    @Test
    void contextLoads() {
    }
}

application-dev.properties文件配置内容:

files.root-directory=${user.home}\\api\\files

application-test.properties文件配置内容(原文笔误标注为application-dev.properties):

files.root-directory=/home/api/var/api/files

项目文件结构截图:
文件结构截图


问题原因

核心是测试类的注解使用和Bean加载方式不符合Spring Boot测试逻辑,具体两点:

  1. 注解混用导致Spring属性注入不生效:@ExtendWith(MockitoExtension.class)是纯Mockito的JUnit5扩展,本身不会启动Spring容器,也不会处理Spring配置加载、属性注入、Bean生命周期逻辑。如果和@SpringBootTest同时标注,且测试类中用@InjectMocks+@Mock的纯Mockito方式实例化Service,得到的是Mockito反射创建的对象,完全脱离Spring容器管理,@Value的属性注入逻辑根本不会执行,字段自然保持null值。
  2. 多余注解干扰配置加载:启动测试类上的@TestPropertySource("classpath:application-test.properties")和@EnableConfigurationProperties都是冗余配置。只要正确指定@ActiveProfiles("test"),Spring Boot会自动加载对应profile的配置文件,手动重复指定反而可能因属性源优先级问题覆盖正常加载逻辑。另外未配置默认application.properties本身不会导致配置加载失败,不是问题诱因。

解决方案

根据测试场景选择对应方案即可:

方案1:需要完整Spring上下文的集成测试

  1. 移除FileServiceTest上的@ExtendWith(MockitoExtension.class)注解。@SpringBootTest已经自带Spring对JUnit5的扩展支持,会自动启动Spring容器、加载对应profile配置、完成属性注入。如果需要Mock容器中的其他依赖Bean,直接用Spring Boot自带的@MockBean注解即可,不需要纯Mockito扩展。
    修改后的测试类示例:
    @SpringBootTest
    @ActiveProfiles("test")
    public class FileServiceTest {
        // 直接注入Spring管理的Service实例
        @Autowired
        private FileService fileService;
    
        // 需要Mock依赖时直接用@MockBean
        // @MockBean
        // private OtherDependency otherDependency;
    }
    
  2. 移除ApiApplicationTests上多余的@TestPropertySource和@EnableConfigurationProperties注解,修改后代码如下:
    @SpringBootTest
    @ActiveProfiles("test")
    class ApiApplicationTests {
        @Test
        void contextLoads() {
        }
    }
    
  3. 确认application-test.properties存放在测试资源目录src/test/resources下,路径和主资源目录的配置文件路径一致,保证测试运行时能被正确扫描。

方案2:不需要启动Spring容器的轻量单元测试

如果不需要加载完整Spring上下文,直接去掉@SpringBootTest相关注解,纯Mockito场景下手动给属性注入测试值即可:

@ExtendWith(MockitoExtension.class)
public class FileServiceTest {
    @InjectMocks
    private FileServiceImpl fileService;
    @Mock
    private OtherDependency otherDependency;

    @BeforeEach
    void setUp() {
        // 通过反射给@Value标注的字段注入测试值
        ReflectionTestUtils.setField(fileService, "fileDirectory", "/test/path/files");
    }

    // 测试用例
}

内容的提问来源于stack exchange,提问作者Ali Behzadian Nejad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:45:38