Spring REST API测试:Mockito thenThrow()后代码不执行问题求助
我来帮你梳理下这个测试用例里的几个关键问题,一步步拆解清楚:
1. Mock对象未正确注入,导致真实方法被执行
你提到已经Mock了BookService,但从测试代码来看,大概率是Mock对象没有正确注入到BookController中,或者bookService本身不是一个有效的Mock实例。
当你执行when(bookService.findBookByName(any())).thenThrow(new Exception())时,如果bookService是真实对象而非Mock对象,这行代码会直接调用真实的findBookByName方法——如果这个真实方法抛出了异常,就会直接触发测试用例的expected = Exception.class条件,导致后续的System.out.println("hello2")和控制器调用代码都不会执行,测试直接“通过”。
解决方法:
确保测试类中正确配置Mockito的注解,让Mock对象被自动注入到控制器里:
@RunWith(MockitoJUnitRunner.class) // JUnit 4用这个,JUnit 5用MockitoExtension public class BookControllerTest { @Mock private BookService bookService; // 声明Mock对象 @InjectMocks private BookController bookController; // 自动将Mock注入到控制器中 // 你的测试方法... }
2. 测试用例期望的异常类型不匹配
看你的控制器代码:
try { Books resultBooks = bookService.findBookByName(bookName); // ... } catch(Exception e){ throw new RuntimeException(); // 这里抛出的是RuntimeException,不是原始的Exception }
当bookService抛出Exception时,控制器会捕获它并重新抛出RuntimeException,但你的测试用例标注的是@Test(expected = Exception.class)——这会导致测试实际抛出的异常和期望的不一致,原本应该失败,但因为前面的Mock问题导致真实方法抛出了Exception,才让测试“巧合”通过。
解决方法:
把测试用例的期望异常改成RuntimeException.class:
@Test(expected = RuntimeException.class) public void getBookDetails_shouldReturn500() throws Exception { // ... }
3. 断言代码永远不会执行
因为测试用例标注了expected = Exception.class,一旦抛出对应异常,测试框架会直接终止测试流程,后面的responseEntity获取和断言代码根本不会运行——这就是为什么不管你断言is2xxSuccessful还是is5xxServerError,测试都能通过的原因,因为断言根本没执行。
解决方法:
如果你想验证控制器抛出异常后的HTTP状态码,建议用MockMvc来模拟HTTP请求,而不是直接调用控制器方法。这样可以完整测试请求处理流程:
@Test public void getBookDetails_shouldReturn500() throws Exception { String bookName = "First"; when(bookService.findBookByName(any())).thenThrow(new Exception()); mockMvc.perform(get("/books/getDetails/{bookName}", bookName)) .andExpect(status().isInternalServerError()); // 验证500状态码 }
使用MockMvc需要在测试类中配置:
@Autowired private MockMvc mockMvc; // 或者在@Before方法中手动初始化 @Before public void setup() { mockMvc = MockMvcBuilders.standaloneSetup(bookController).build(); }
总结
现在的测试用例因为Mock注入问题,导致真实方法被调用,加上异常类型不匹配、断言未执行,才出现了你看到的奇怪现象。按照上面的步骤修正Mock配置、调整异常期望、改用MockMvc测试HTTP请求,就能得到正确的测试结果了。
内容的提问来源于stack exchange,提问作者Rishabh Sharma

