You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 01:22:38