使用MockMvc测试Controller时无法mock依赖Service返回结果的原因是什么
核心原因汇总
1. Mock对象未正确注入Controller实例
standaloneSetup 模式不会自动完成依赖注入,需要手动将你创建的mock OrderService实例传入OrderController的构造函数/setter,再把这个手动组装好的Controller实例传给standaloneSetup。
常见错误操作是直接new一个无参的OrderController传入standaloneSetup,这个Controller实例里的OrderService还是空的或者是真实实现类,和你打桩的mock对象不是同一个实例,自然不会触发你预设的返回值。
正确初始化示例:
// 先创建mock的Service OrderService mockOrderService = Mockito.mock(OrderService.class); // 手动组装Controller,把mock的Service传进去 OrderController orderController = new OrderController(mockOrderService); // 用组装好的Controller初始化MockMvc MockMvc mockMvc = MockMvcBuilders.standaloneSetup(orderController).build();
2. 打桩方法的参数匹配失败
你给findFilSortOrders打桩时传入的参数,和Controller实际调用时传入的参数不一致时,Mockito不会返回你预设的列表,会默认返回空集合。
比如你打桩时写的是:
// 硬编码参数打桩 when(mockOrderService.findFilSortOrders(1, 10, "createTime")).thenReturn(testList);
但Controller实际调用时传的排序参数是updateTime,或者分页参数不匹配,打桩就不会生效。
排查方案:打桩时用参数匹配器匹配任意参数,验证是否是参数问题:
when(mockOrderService.findFilSortOrders(anyInt(), anyInt(), anyString())).thenReturn(testList);
3. 打桩时机错误
如果在初始化MockMvc之后才给Service打桩,或者打桩的mock对象和注入到Controller的mock对象不是同一个实例,也会导致打桩不生效。需要保证打桩的对象就是Controller里依赖的那个实例,且打桩操作在接口调用之前完成。
4. 业务逻辑额外处理
排除前面三个问题后,再检查Controller拿到Service返回的列表后有没有做过滤、删除等操作,或者Jackson序列化配置有没有把空集合/空值过滤掉,导致最终返回的列表长度为0。
内容的提问来源于stack exchange,提问作者DozezQuest

