Spring Boot控制器JUnit测试when().thenReturn()失效如何解决?
问题原因
- 你的
FundController中FundUtil是直接new出来的实例,没有交给Spring容器管理,测试类中的msUtil和Controller实际使用的不是同一个对象,且你测试类里的msUtil是自己创建的普通对象,不是Mockito生成的Mock对象,调用when().thenReturn()时才会抛出MissingMethodInvocationException异常:Mockito只允许对Mock/Spy对象的方法进行打桩。 - 你在测试类的
setUp方法中手动覆盖了Spring注入的@MockBean FundDAO msDAO,自己new了一个DAO实例,导致你打桩的对象和Controller中注入的对象不是同一个,Mock逻辑自然不生效。 - 测试方法中调用的请求路径和Controller定义的路径不一致,且缺少必填的
@RequestBody请求体参数,就算Mock逻辑正常也会返回400/404错误。 - 如果你用的是JUnit4,缺少
@RunWith(SpringRunner.class)注解会导致@MockBean不生效。
修复步骤
1. 修正Controller的依赖注入逻辑
不要手动实例化依赖,全部交给Spring注入:
@RestController public class FundController { @Autowired private FundDAO msDAO; @Autowired // 把FundUtil也改成注入 private FundUtil msUtil; // 其余业务代码保持不变 }
2. 修正测试类配置
移除手动实例化Mock对象的逻辑,把FundUtil也注册为MockBean,JUnit4环境添加@RunWith注解:
@RunWith(SpringRunner.class) // JUnit4必须加,JUnit5可省略 @WebMvcTest(controllers = FundController.class) @ActiveProfiles("test") public class FundTest { @Autowired private MockMvc mockMvc; @MockBean private FundDAO msDAO; @MockBean // 新增,让Spring把Controller中的FundUtil替换为Mock对象 private FundUtil msUtil; private fundName fundName; @Before public void setUp() { fundName = MockData.getfundName(); // 删掉下面两行手动实例化的代码,不要覆盖Spring注入的Mock对象 // msUtil = new FundsOrchestratorUtil(); // msDAO = new FundsOrchestratorDAO(); }
3. 修正测试方法逻辑
补全请求参数,修正请求路径,补充所有需要Mock的方法:
@Test public void shouldFetchAllUsers() throws Exception { FundSearchResponse fundSearchResponse = MockData.getfundsSearchResponse(); // 对Mock对象的方法打桩 when(msUtil.validatefundSearchRequest(any(fundName.class), anyInt())).thenReturn(true); // 补充buildServiceResponse方法的打桩,避免返回null导致异常 when(msUtil.buildServiceResponse(Constants.CODE_200_SUCCESS)).thenReturn(/* 构造你期望返回的ServiceResponse对象 */); when(msDAO.fundNameSearch(anyString(), anyInt())).thenReturn(fundSearchResponse); // 构造JSON请求体,补全请求参数 ObjectMapper objectMapper = new ObjectMapper(); String requestJson = objectMapper.writeValueAsString(fundName); this.mockMvc.perform(post("/v1/fund/search") // 修正路径,和Controller保持一致 .contentType(MediaType.APPLICATION_JSON) .content(requestJson) .param("limit", "5")) .andExpect(status().isOk()); }
内容的提问来源于stack exchange,提问作者Masoom Raza
相关产品推荐
相关产品推荐

