Mockito无法模拟HttpURLConnection内部变量,测试报错求助
解决Mockito UnnecessaryStubbingException问题
问题根源
你写的测试代码里mock了URL和HttpURLConnection对象,但业务方法中是直接通过new URL(crmEndPoint)创建URL实例,完全没用到你声明的mockUrl对象。这就导致你给mockUrl.openConnection()、mockConnection.connect()、mockConnection.disconnect()做的存根逻辑根本不会被执行,Mockito检测到无用存根后就抛出了UnnecessaryStubbingException。
另外补充一点:Mockito对void方法的mock默认就是什么都不做,所以你写的doNothing().when(mockConnection).connect();和doNothing().when(mockConnection).disconnect();本身就是多余的,完全可以删掉。
解决方案
有两种常见的解决思路,根据你的需求选择:
方案1:改造业务代码,抽离URL创建逻辑(推荐,符合依赖注入思想)
把业务方法中直接new URL的逻辑抽成一个可被mock的方法,这样测试时可以替换成mock的URL实例:
首先修改业务类SelfServiceCoreClaimImpl:
// 新增一个protected方法,用于创建URL,方便测试时mock protected URL createUrl(String endpoint) throws MalformedURLException { return new URL(endpoint); } public boolean isSelfServicePortalServerAvailable(String crmEndPoint) { boolean isServerAvailable = false; URL url = null; HttpURLConnection connection = null; try { url = createUrl(crmEndPoint); // 调用抽离后的方法 connection = (HttpURLConnection) url.openConnection(); connection.connect(); isServerAvailable = true; connection.disconnect(); } catch (MalformedURLException e) { log.error(e.getMessage()); } catch (IOException e) { log.error(e.getMessage()); } return isServerAvailable; }
然后修改测试类,用Spy来mock这个抽离的方法:
@Spy @InjectMocks private SelfServiceCoreClaimImpl selfServiceCoreClaimImpl = new SelfServiceCoreClaimImpl(restTemplate); @Mock private HttpURLConnection mockConnection; @Test public void testIsSelfServicePortalServerAvailable_Success() throws IOException { // 创建mock的URL实例 URL mockUrl = Mockito.mock(URL.class); // 当调用createUrl方法传入指定地址时,返回我们的mockUrl doReturn(mockUrl).when(selfServiceCoreClaimImpl).createUrl("http://test-url.com"); // mock URL的openConnection方法返回mock的连接 when(mockUrl.openConnection()).thenReturn(mockConnection); boolean result = selfServiceCoreClaimImpl.isSelfServicePortalServerAvailable("http://test-url.com"); assertTrue(result); // 可选:验证关键方法是否被调用,确保逻辑符合预期 verify(mockUrl).openConnection(); verify(mockConnection).connect(); verify(mockConnection).disconnect(); }
方案2:用PowerMock mock构造方法(无需修改业务代码)
如果不想改动业务代码,可以用PowerMock来mocknew URL()的行为,因为Mockito默认不支持mock构造方法。
首先确保你的项目引入了PowerMock的对应版本依赖,然后编写测试类:
@RunWith(PowerMockRunner.class) @PrepareForTest({SelfServiceCoreClaimImpl.class, URL.class}) public class SelfServiceCoreClaimImplTest { @Mock private HttpURLConnection mockConnection; @Mock private RestTemplate restTemplate; @InjectMocks private SelfServiceCoreClaimImpl selfServiceCoreClaimImpl = new SelfServiceCoreClaimImpl(restTemplate); @Test public void testIsSelfServicePortalServerAvailable_Success() throws IOException { // mock new URL("http://test-url.com")返回我们的mockUrl实例 URL mockUrl = Mockito.mock(URL.class); PowerMockito.whenNew(URL.class).withArguments("http://test-url.com").thenReturn(mockUrl); // mock URL的openConnection方法返回mock连接 when(mockUrl.openConnection()).thenReturn(mockConnection); boolean result = selfServiceCoreClaimImpl.isSelfServicePortalServerAvailable("http://test-url.com"); assertTrue(result); // 验证方法调用 verify(mockUrl).openConnection(); verify(mockConnection).connect(); verify(mockConnection).disconnect(); } }
内容的提问来源于stack exchange,提问作者dhS
相关产品推荐
相关产品推荐

