Kotlin Spring @WebMvcTest测试方法耗时差异大原因咨询
问题背景
在Kotlin技术栈的Spring项目中使用@WebMvcTest编写集成测试时,不同测试方法执行速度差异较大:test1耗时仅31ms,test2稳定耗时达到800ms,暂未定位到明确诱因。
测试代码实现
@Test fun `test1`() { // given val folderList = mutableListOf( Folder.FolderListResponse(1L, "emoji1", "child1"), Folder.FolderListResponse(2L, "emoji2", "child2") ) every { folderService.findFolderChildList(any()) } returns folderList // when val resultAction = util.getResultAction("/api/v1/folder/1/children", mockMvc) // then resultAction .andExpect(status().isOk) .andExpect(jsonPath("$[0].folderId").value(1L)) .andExpect(jsonPath("$[0].emoji").value("emoji1")) .andExpect(jsonPath("$[0].name").value("child1")) .andExpect(jsonPath("$[1].folderId").value(2L)) .andExpect(jsonPath("$[1].emoji").value("emoji2")) .andExpect(jsonPath("$[1].name").value("child2")) } @Test fun `test2`() { // given val info1 = AccountDto.FolderBelongAccountInfo(1, "info1", "images") val info2 = AccountDto.FolderBelongAccountInfo(2, "info2", "images") val expected = AccountDto.FolderBelongAccountListDto(mutableListOf(info1, info2)) every { folderService.getAccountListAtRootFolder(any()) } returns expected // when val resultAction = util.getResultAction("/api/v1/folder/belong/1", mockMvc) // then resultAction .andExpect(status().isOk) } fun getResultAction(uri: String, mockMvc: MockMvc): ResultActions { return mockMvc.perform( MockMvcRequestBuilders.get(uri) .header("AccessToken", "token") .header("RefreshToken", "retoken") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .characterEncoding(StandardCharsets.UTF_8.toString()) ) }
测试执行日志
test1执行日志
MockHttpServletRequest: HTTP Method = GET Request URI = /api/v1/folder Parameters = {} Headers = [Content-Type:"application/json;charset=UTF-8", AccessToken:"token", RefreshToken:"retoken", Accept:"application/json"] Body = null Session Attrs = {} Handler: Type = com.yapp.web2.domain.folder.controller.FolderController Method = com.yapp.web2.domain.folder.controller.FolderController#findAll(HttpServletRequest) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8"] Content type = application/json;charset=UTF-8 Body = {} Forwarded URL = null Redirected URL = null Cookies = []
test2执行日志
MockHttpServletRequest: HTTP Method = GET Request URI = /api/v1/folder/belong/1 Parameters = {} Headers = [Content-Type:"application/json;charset=UTF-8", AccessToken:"token", RefreshToken:"retoken", Accept:"application/json"] Body = null Session Attrs = {} Handler: Type = com.yapp.web2.domain.folder.controller.FolderController Method = com.yapp.web2.domain.folder.controller.FolderController#getAccountList(long) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8"] Content type = application/json;charset=UTF-8 Body = {"list":[{"id":1,"name":"info1","profileImage":"images"},{"id":2,"name":"info2","profileImage":"images"}]} Forwarded URL = null Redirected URL = null Cookies = []
性能差异原因
核心差异来自Jackson序列化器的冷启动类加载与初始化开销,和测试业务逻辑本身无关:
- 从执行日志能看出,当前运行的test1根本没走到预期的子文件夹查询逻辑:代码里写的请求路径是
/api/v1/folder/1/children,但实际日志里的请求URI是/api/v1/folder,命中的是findAll接口,返回响应体是空对象{}。序列化空对象不需要加载复杂自定义DTO的序列化逻辑,几乎无额外开销,所以耗时极短。 - test2是测试类中第一个触发Jackson序列化自定义嵌套DTO的用例:
@WebMvcTest上下文中的Jackson序列化模块是懒加载的,第一次遇到非简单类型的自定义DTO(也就是这里的FolderBelongAccountListDto及内部嵌套的FolderBelongAccountInfo类)时,需要完成类反射扫描、对应字段序列化器实例化、类型序列化缓存构建等一系列初始化操作,这部分冷启动开销通常在500-1000ms级别,会计入第一个触发该操作的测试用例耗时里。 - 这个现象可以很容易复现验证:调整测试执行顺序,或者在test2之前加一个返回任意自定义DTO响应的测试,就会发现耗时高的用例会变成第一个触发复杂DTO序列化的测试,后续所有涉及同类型序列化的测试,耗时都会降到几十毫秒的正常水平。
内容的提问来源于stack exchange,提问作者Leelee
相关产品推荐
相关产品推荐

