Spring RestController含LocalDate类型@RequestParam的单元测试报错如何解决
问题根因
你自定义的测试配置类ControllersTestConfig没有加载Spring MVC的类型转换组件,@DateTimeFormat注解对应的String转java.time.LocalDate转换器未被注册到测试上下文,导致请求参数的日期字符串无法转换为接口要求的LocalDate类型,抛出500错误。
解决方案
方案1:改用@WebMvcTest注解(推荐,专用于Controller单元测试)
Spring Boot提供的@WebMvcTest会自动加载所有MVC相关的基础组件(包括日期转换器、参数解析器等),不需要手动写配置类,同时仅扫描Controller层的Bean,测试速度更快。
修改后的测试代码如下:
// 替换原来的三个类级别注解,指定要测试的Controller @WebMvcTest(OrderController.class) // 如果用到了Spring Security的@PreAuthorize,加这个注解开启安全相关的测试支持 // Spring Security 6+ 用@EnableMethodSecurity(prePostEnabled = true) // 旧版本用@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity(prePostEnabled = true) public class OrderControllerTest { @Autowired private MockMvc mockMvc; // 用@MockBean来替换上下文里的ServiceOrder为Mock对象 @MockBean private ServiceOrder serviceOrder; // 不需要手动初始化MockMvc,也不需要自定义配置类 @Test public void showCompletedOrdersInPerTest() throws Exception { Mockito.when(serviceOrder.completedOrdersInPeriod(Mockito.any(), Mockito.any())).thenReturn(1L); // 注意:接口加了@PreAuthorize要求ROLE_ADMIN权限,测试请求需要带对应权限,否则会返回403 mockMvc.perform(MockMvcRequestBuilders.post("/orders/completed/period") .param("start", "2020-01-01") .param("end", "2022-01-01") // 加模拟的ADMIN权限 .with(SecurityMockMvcRequestPostProcessors.user("admin").roles("ADMIN"))) .andExpect(MockMvcResultMatchers.status().isOk()); } }
这个方案不需要保留原来的ControllersTestConfig配置类,简化测试逻辑。
方案2:保留现有配置,手动添加MVC转换支持
如果你不想修改现有测试的结构,只需要在测试配置类上加@EnableWebMvc注解,即可自动注册包括日期转换器在内的所有MVC基础组件:
@EnableWebMvc // 新增这个注解 // 如果用到Spring Security,同时加权限开启注解 @EnableMethodSecurity(prePostEnabled = true) public class ControllersTestConfig { @Bean public ServiceOrder serviceOrder() { return Mockito.mock(ServiceOrder.class); } @Bean public OrderController orderController(){ return new OrderController(); } }
修改后测试请求同样需要添加模拟的ADMIN权限,否则参数转换问题修复后会返回403错误,权限添加方式参考方案1的请求配置即可。
内容的提问来源于stack exchange,提问作者Anton
相关产品推荐
相关产品推荐

