Spring Boot@Value注入失效:Service层值为0,测试层正常
问题原因及解决方案
核心原因分析
- 启动类误用测试注解:启动类
DemoApplication上的@TestPropertySource是测试专用注解,生产环境启动时不会生效,属于冗余配置,虽不直接导致注入失败,但易引发配置逻辑混淆。 - Service层冗余配置干扰:
RoomHistoryService上的@PropertySource("classpath:application.properties")完全多余——Spring Boot默认会自动加载classpath下的application.properties,重复指定可能引发配置加载优先级异常,间接导致属性注入失效。 - 组件扫描范围可能不完整:启动类仅扫描
service包,若RoomHistoryDao所在包不在扫描范围内,Service虽能初始化,但依赖注入和属性注入可能出现异常(若Dao也在service包下可忽略,但需确保扫描范围覆盖所有Spring管理的组件)。 - 测试类存在假阳性通过:测试中用
@InjectMocks创建Service实例是Mockito的实例化方式,不会触发Spring的属性注入——你测试断言用的是测试类自身注入的变量,而非Service内部的guestRecordsInRoomHistory,所以测试看似通过,实则Service未被正确注入。
修复步骤
1. 修正启动类配置
移除启动类上的@TestPropertySource,若启动类放在根包下,可直接省略@ComponentScan(@SpringBootApplication会自动扫描其所在包及子包):
@SpringBootApplication public class DemoApplication { private static final Logger logger = LoggerFactory.getLogger(DemoApplication.class); public static void main(String[] args) { logger.info("Application started. Performing startup operations..."); SpringApplication.run(DemoApplication.class, args); } }
若需指定扫描范围,确保覆盖所有组件包:
@SpringBootApplication(scanBasePackages = {"service", "dao"}) // 替换为实际包名 public class DemoApplication { // ... 其余代码不变 }
2. 清理Service层冗余配置
移除RoomHistoryService上的@PropertySource注解:
@Service public class RoomHistoryService implements Serializable { @Value("${guest.records.in.room.history}") private int guestRecordsInRoomHistory; @Autowired private RoomHistoryDao roomHistoryDao; // ... 其余代码不变 }
3. 修复测试类逻辑
让Spring管理Service实例,确保属性注入生效,替换@InjectMocks为@Autowired,同时移除不必要的@TestPropertySource:
@SpringBootTest class RoomHistoryServiceTest { @Value("${guest.records.in.room.history}") private int guestRecordsInRoomHistory; @MockBean // 用@MockBean让Spring管理Mock实例 private RoomHistoryDao roomHistoryDao; @Autowired // 让Spring注入Service实例,确保@Value生效 private RoomHistoryService roomHistoryService; // ... 其余测试代码不变 @Test void testGetRoomHistoriesByRoomNumber_ReturnsLimitedRoomHistories() { int roomNumber = ROOM_NUMBER; List<RoomHistory> mockRoomHistories = Arrays.asList(ROOM_HISTORY_JOHN, ROOM_HISTORY_ALICE, ROOM_HISTORY_BOB); when(roomHistoryDao.getRoomHistoriesByRoomNumber(roomNumber)).thenReturn(mockRoomHistories); List<RoomHistoryDto> limitedRoomHistories = roomHistoryService.getRoomHistoriesByRoomNumber(roomNumber); verify(roomHistoryDao, times(1)).getRoomHistoriesByRoomNumber(roomNumber); // 此时断言的是Service中实际注入的值,测试更准确 assertEquals(guestRecordsInRoomHistory, limitedRoomHistories.size()); } }
验证方法
在getRoomHistoriesByRoomNumber方法中添加日志打印,确认属性是否正确注入:
logger.info("当前配置的记录限制数:{}", guestRecordsInRoomHistory);
内容的提问来源于stack exchange,提问作者Marek Grzesiak
相关产品推荐
相关产品推荐

