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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:34:52