JUnit测试调用Controller方法时遇ClassNotLoadException求助
解决JUnit测试Controller时的ClassNotLoadException及断点无法进入问题
我来帮你分析下这个问题:你遇到的com.sun.jdi.ClassNotLoadException本质上是因为Mockito的使用方式不对——你现在用@Mock注解创建的是AvamarController的模拟代理对象,而不是Spring容器管理的真实Controller实例。这个Mock对象的方法默认是空实现(或者Mockito的默认占位行为),根本不会执行你写的Controller里的真实代码,所以调试断点无法触发,还会因为代理类的加载机制问题抛出异常。另外你传了null作为Model参数,这也是潜在的空指针风险。
下面给你两种针对性的解决方案:
方案一:测试真实Controller逻辑(推荐)
如果你想测试Controller的真实业务逻辑(比如验证model的属性是否正确、视图名称是否符合预期),应该用@InjectMocks创建真实的Controller实例,同时Mock它依赖的业务对象(比如avamarOSBO),避免调用真实的服务层代码。
修改后的测试类代码如下:
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.ui.Model; import org.springframework.web.servlet.ModelAndView; import com.emc.brsit.avamar.vo.AvamarAllComponentsVO; import com.emc.brsit.common.util.CustomCompGuideException; // 假设你的业务对象类型是AvamarOSBO,需要根据实际类名修改 import com.emc.brsit.avamar.service.AvamarOSBO; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:/Project/applicationContext servlet.xml") public class AvamarControllerTest { private final static Logger LOGGER = LoggerFactory .getLogger(AvamarControllerTest.class); // 创建真实的Controller实例,并自动注入下面的Mock依赖 @InjectMocks private AvamarController avamar; // Mock Controller依赖的业务对象,避免调用真实服务 @Mock private AvamarOSBO avamarOSBO; @Mock private AvamarAllComponentsVO avamarComponent; @Mock private Model model; // 用Mock替代null,避免空指针 @Before public void setupMock() { MockitoAnnotations.initMocks(this); // 提前Mock业务对象的方法返回值,让Controller逻辑能正常执行 // 示例:根据实际方法返回值类型修改xxx Mockito.when(avamarOSBO.getApp_Hype_Feat_Filters("Features")).thenReturn(xxx); Mockito.when(avamarOSBO.getClientOSGroupedBY()).thenReturn(xxx); // 其他业务方法同理,按需Mock } @Test public void testGetCompGuidePage() { String productVersion ="7.5"; ModelAndView modelView = null; try { modelView = avamar.getCompGuidePage(productVersion , avamarComponent, model ); // 断言验证:判断返回的视图名称是否符合预期 org.junit.Assert.assertEquals("AvamarCompGuideApp", modelView.getViewName()); // 还可以验证model的属性是否被正确添加,比如: // Mockito.verify(model).addAttribute("link", productVersion); } catch (CustomCompGuideException e) { e.printStackTrace(); org.junit.Assert.fail("测试失败,抛出异常:" + e.getMessage()); } } }
这个方案的核心逻辑:
@InjectMocks会初始化真实的AvamarController实例,并将所有@Mock标注的依赖(比如avamarOSBO)自动注入到Controller中。- 你可以通过
Mockito.when()来指定业务对象方法的返回值,确保Controller的逻辑能完整执行,同时不会触发真实的数据库/服务调用。 - 用
@Mock模拟Model对象,避免传null导致空指针。
方案二:让Mock对象执行真实方法(仅适用于特定场景)
如果你的需求只是想让Mock的Controller对象执行真实的方法(比如测试上层调用逻辑),可以用thenCallRealMethod()告诉Mockito执行真实的方法实现。但注意:Controller的依赖(比如avamarOSBO)必须提前Mock,否则会出现空指针。
修改后的测试方法示例:
@Test public void testGetCompGuidePage() { String productVersion ="7.5"; Model model = Mockito.mock(Model.class); ModelAndView modelView = null; // 让Mock的Controller对象执行真实的getCompGuidePage方法 Mockito.when(avamar.getCompGuidePage(productVersion, avamarComponent, model)) .thenCallRealMethod(); try { modelView = avamar.getCompGuidePage(productVersion , avamarComponent, model ); // 这里可以添加断言逻辑 } catch (CustomCompGuideException e) { e.printStackTrace(); } }
注意事项:
- 这种方式依然需要MockController的所有依赖(比如
avamarOSBO),否则会因为依赖为null抛出空指针异常。 - 此方案更适合测试Controller方法的上层调用,而非验证Controller内部逻辑。
问题总结
- 你之前的测试用
@Mock创建的是Controller的代理对象,不是真实实例,所以不会执行真实代码,断点无法触发,进而抛出类加载异常。 - 传
null作为Model参数是潜在的空指针风险,必须用Mock对象替代。
内容的提问来源于stack exchange,提问作者Gaurav
相关产品推荐
相关产品推荐

