编写saveColor单元测试时遇modelMapper.map()未调用错误求助
核心问题分析
1. Mock对象未被Spring容器使用
你在测试类中用@Mock标注ModelMapper,但@Mock仅会创建一个mock对象,不会替换Spring上下文里的真实ModelMapper实例。Controller依赖的是Spring容器中的真实ModelMapper,而非你mock的对象,所以自然不会触发mock对象的map方法,导致verify校验失败。
2. 请求参数可能未通过校验
测试用例中colorDTO的hex值为"1##r",如果ColorDTO的hex字段带有校验注解(比如@Pattern要求合法十六进制格式),这个值会触发校验错误,bindingResult会存在错误信息,代码直接返回HttpStatus.BAD_REQUEST,根本不会执行到modelMapper.map()的逻辑。
具体修复步骤
步骤1:替换@Mock为@MockBean
将测试类中的@Mock private ModelMapper modelMapper;改为@MockBean private ModelMapper modelMapper;。@MockBean会自动将mock对象注入Spring容器,替换掉原本的真实ModelMapper实例,确保Controller使用的是你mock的对象。
步骤2:使用合法的请求参数
修改colorDTO的hex值为符合校验规则的内容,比如合法的十六进制颜色值"#FF0000",确保校验通过,代码能执行到modelMapper.map()的逻辑。
步骤3:优化Mock匹配逻辑(可选)
建议使用any(ColorDTO.class)和eq(Color.class)来匹配方法参数,避免因对象equals判断失败导致mock不生效。
修改后的测试代码示例
@SpringBootTest @AutoConfigureMockMvc public class ColorMasterControllerTest { @Autowired private MockMvc mockMvc; @Autowired private ObjectMapper objectMapper; @MockBean // 替换为@MockBean private ModelMapper modelMapper; @MockBean private ColorMaster colorMaster; @Test void savedColor_ValidInput_ReturnCreated() throws Exception { // 使用合法的十六进制颜色值 ColorDTO colorDTO = new ColorDTO(1L, "red", "#FF0000"); Color color = new Color(1L, "red", "#FF0000"); // 优化参数匹配逻辑 when(modelMapper.map(any(ColorDTO.class), eq(Color.class))).thenReturn(color); when(colorMaster.saveColor(any(Color.class))).thenReturn(color); MvcResult result = mockMvc.perform(post("/api/color") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(colorDTO))) .andExpect(status().isCreated()) .andReturn(); verify(modelMapper, times(1)).map(any(ColorDTO.class), eq(Color.class)); verify(colorMaster, times(1)).saveColor(any(Color.class)); then(result.getResponse().getContentAsString()).isEqualTo(objectMapper.writeValueAsString(color)); } }
额外优化建议
如果仅需测试Controller逻辑,推荐使用@WebMvcTest(ColorMasterController.class)代替@SpringBootTest,它只会加载Controller相关组件,测试启动更快、更轻量化:
@WebMvcTest(ColorMasterController.class) @ExtendWith(MockitoExtension.class) public class ColorMasterControllerTest { // 后续代码与上述修改一致 }
内容的提问来源于stack exchange,提问作者Art yudi

