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
相关产品推荐
相关产品推荐

