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

JUnit5测试含私有@Value属性的Spring控制器条件判断问题

问题描述

控制器代码:

@Value("${custom.properties.list}")
private List<String> stringList;

final DataService dataService;

@PostMapping("/")
public ResponseEntity<?> createValue(
        @Valid @RequestBody final ObjectDto dto,
        @RequestHeader(value = "headerField") final String headerValue) {

    if (this.stringList.stream().noneMatch(headerValue::startsWith)) {
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body("error 403");
    }

    Long idResult = this.dataService.create(dto, headerValue);

    if (Objects.equals(idResult, -1L)) {
        return ResponseEntity.status(HttpStatus.204).body("error 204");
    }

    return new ResponseEntity<>(idResult, HttpStatus.CREATED);
}

测试需求:假设stringList包含"ABC", "EFG", "HIJ",测试当headerValue以列表中某个值开头时,控制器返回201或204状态码。

当前测试代码:

@Test
void testCreateValue_1() throws Exception {

    String requestBody = new String(Files.readAllBytes(Paths.get("src/test/resources/post/postRequest_1.json")));

    MyObjectData data = mapper.readValue(requestBody, MyObjectData.class);

    Mockito.when(dataService.create(data, "ABC")).thenReturn(1L);

    mvc.perform(post("/")
                    .header("Nom-Application", "ABC")
                    .content(requestBody)
                    .contentType(MediaType.APPLICATION_JSON))
            .andDo(print())
            .andExpect(MockMvcResultMatchers.status().isCreated());
}

遇到的问题:测试返回403状态码失败,排查发现测试时stringList中只有"${custom.properties.list}",属性未正确注入,同时测试请求头名称与控制器定义不匹配。

解决方案

1. 修正请求头名称错误

控制器中@RequestHeader指定的参数名是headerField,但测试代码里用的是Nom-Application,这会导致控制器获取不到正确的header值,直接触发403拦截。修改测试中的header名称:

mvc.perform(post("/")
                .header("headerField", "ABC") // 修正为控制器要求的header名称
                .content(requestBody)
                .contentType(MediaType.APPLICATION_JSON))

2. 正确注入测试所需的stringList属性

针对@Value属性未正确加载的问题,有三种常用解决方式:

方式一:使用@TestPropertySource直接指定属性

在测试类上添加注解,直接设置custom.properties.list的值:

@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = "custom.properties.list=ABC,EFG,HIJ")
class YourControllerTest {
    // 测试代码...
}

方式二:使用@DynamicPropertySource动态配置属性

如果需要更灵活的属性设置逻辑,可通过该注解动态注册属性:

@SpringBootTest
@AutoConfigureMockMvc
class YourControllerTest {

    @DynamicPropertySource
    static void dynamicProperties(DynamicPropertyRegistry registry) {
        registry.add("custom.properties.list", () -> "ABC,EFG,HIJ");
    }

    // 测试代码...
}

方式三:通过反射直接注入字段

如果不想修改测试环境的全局属性配置,可通过反射直接给控制器的stringList字段赋值:

@Autowired
private YourController controller;

@Test
void testCreateValue_1() throws Exception {
    // 反射注入目标列表
    Field stringListField = YourController.class.getDeclaredField("stringList");
    stringListField.setAccessible(true);
    stringListField.set(controller, Arrays.asList("ABC", "EFG", "HIJ"));

    // 后续测试逻辑...
}

3. 确保请求体参数匹配

测试中用MyObjectData解析请求体,但控制器接收的是ObjectDto,可能导致Mockito的mock匹配失效。建议使用参数匹配器兼容类型差异:

Mockito.when(dataService.create(any(ObjectDto.class), eq("ABC"))).thenReturn(1L);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:20:55