MockMvc测试中注册WebMvcConfigurer以启用请求格式化的方法
问题:Spring Boot控制器测试中如何加载WebConfig的格式化配置?
我有一个Spring Boot后端API,通过以下配置对API接收的载荷进行格式化:
@Configuration class WebConfig : WebMvcConfigurer { override fun addFormatters(registry: FormatterRegistry) { registerSpringFormatters(registry) // 自定义格式化方法 } }
现在需要编写单元测试,验证控制器接收的输入是否被正确格式化,已编写如下测试代码:
class MyApiControllerTest { private val myService: OrderedProjectVintagesService = mock() private val myController = MyController( myService = myService ) private lateinit var mockMvc: MockMvc @Test fun `test comma in attributes`() { val input = Request( projectTypes = listOf("type1,2"), ) val sortedSummaries = listOf( Summary( currentPrice = BigDecimal("35"), projectName = "Project 1" ) ) whenever( myService.listProjects( projectTypes = input.projectTypes!! ) ).thenReturn(sortedSummaries) mockMvc = MockMvcBuilders .standaloneSetup(productItemOrderingController) .build() mockMvc.perform( get("/api/ordered-projects") .param("projectTypes", "type1,2") ).andExpect(status().isOk) verify(myService, times(1)).listProjects( projectTypes = input.projectTypes!!, ) } }
但测试失败,原因是测试过程中WebConfig未被注册。请问如何让测试生效,使输入能通过WebConfig被正确格式化?
解决方案
方法1:使用@WebMvcTest注解自动加载配置
改用Spring Boot提供的@WebMvcTest注解启动测试上下文,它会自动扫描并加载实现WebMvcConfigurer的配置类(包括你的WebConfig),同时仅初始化控制器相关Bean,适合控制器层集成测试:
@WebMvcTest(MyController::class) class MyApiControllerTest { @Autowired private lateinit var mockMvc: MockMvc @MockBean private lateinit var myService: OrderedProjectVintagesService @Test fun `test comma in attributes`() { val sortedSummaries = listOf( Summary( currentPrice = BigDecimal("35"), projectName = "Project 1" ) ) // 注意:这里参数要对应格式化后的结果 whenever( myService.listProjects( projectTypes = listOf("type1", "2") ) ).thenReturn(sortedSummaries) mockMvc.perform( get("/api/ordered-projects") .param("projectTypes", "type1,2") ).andExpect(status().isOk) verify(myService, times(1)).listProjects( projectTypes = listOf("type1", "2") ) } }
方法2:在StandaloneSetup中手动注册格式化规则
如果坚持使用MockMvcBuilders.standaloneSetup做纯单元测试,可以手动将WebConfig的格式化逻辑注册到测试的MockMvc实例中:
class MyApiControllerTest { private val myService: OrderedProjectVintagesService = mock() private val myController = MyController(myService = myService) private lateinit var mockMvc: MockMvc @BeforeEach fun setup() { val webConfig = WebConfig() mockMvc = MockMvcBuilders .standaloneSetup(myController) .apply { // 将WebConfig的格式化规则注册到测试用的转换服务中 webConfig.addFormatters(this.formattingConversionService) } .build() } @Test fun `test comma in attributes`() { val sortedSummaries = listOf( Summary( currentPrice = BigDecimal("35"), projectName = "Project 1" ) ) whenever( myService.listProjects( projectTypes = listOf("type1", "2") ) ).thenReturn(sortedSummaries) mockMvc.perform( get("/api/ordered-projects") .param("projectTypes", "type1,2") ).andExpect(status().isOk) verify(myService, times(1)).listProjects( projectTypes = listOf("type1", "2") ) } }
内容的提问来源于stack exchange,提问作者Chamila Wijayarathna
相关产品推荐
相关产品推荐

