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

Spring Boot@Value注入失效:Service层值为0,测试层正常

问题原因及解决方案

核心原因分析

  1. 启动类误用测试注解:启动类DemoApplication上的@TestPropertySource是测试专用注解,生产环境启动时不会生效,属于冗余配置,虽不直接导致注入失败,但易引发配置逻辑混淆。
  2. Service层冗余配置干扰:RoomHistoryService上的@PropertySource("classpath:application.properties")完全多余——Spring Boot默认会自动加载classpath下的application.properties,重复指定可能引发配置加载优先级异常,间接导致属性注入失效。
  3. 组件扫描范围可能不完整:启动类仅扫描service包,若RoomHistoryDao所在包不在扫描范围内,Service虽能初始化,但依赖注入和属性注入可能出现异常(若Dao也在service包下可忽略,但需确保扫描范围覆盖所有Spring管理的组件)。
  4. 测试类存在假阳性通过:测试中用@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:32:26