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

使用Mockito模拟HttpUrlConnection调用时遇连接拒绝错误

问题分析与解决方案

核心问题

测试抛出Connection refused的本质是mock的URL实例未被实际代码使用,导致真实HTTP连接被创建,尝试连接不存在的服务。具体原因如下:

  1. URL构造参数不匹配
    原方法中serverUrl是硬编码的"some url",但测试里PowerMockito.whenNew(URL.class)指定的参数是"http://localhost:8080/sdk/caas/v1/",两者不一致,导致mock的URL不会被返回,代码仍会创建真实的URL实例,触发真实网络请求。

  2. 缺少PowerMockito的必要配置
    使用PowerMockito.whenNew需要额外注解支持,否则mock逻辑不生效:

    • 测试类需用@RunWith(PowerMockRunner.class)标注
    • 需要@PrepareForTest({ControllerHelper.class})指定要mock的目标类(URL实例化发生在ControllerHelper内部)
  3. OutputStream验证的潜在问题
    直接用verify(os, times(1)).write("...".getBytes())可能因字节数组对象引用不一致导致验证失败,建议用参数匹配器优化。

修复步骤

步骤1:对齐URL参数

要么把原方法中的serverUrl改成和测试一致的值,要么修改测试中的mock参数匹配原方法的"some url":

PowerMockito.whenNew(URL.class).withArguments("some url").thenReturn(url);

更优雅的方式是把serverUrl提取为类常量,方便测试和维护:

public class ControllerHelper {
    public static final String SERVER_URL = "some url"; // 提取为常量

    public static Object callApi(String jsonPayload) throws IOException {
        URL url = new URL(SERVER_URL);
        // ... 其余代码不变
    }
}

测试中直接引用该常量:

PowerMockito.whenNew(URL.class).withArguments(ControllerHelper.SERVER_URL).thenReturn(url);

步骤2:添加PowerMockito注解

在测试类上添加必要注解:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ControllerHelper.class})
public class ControllerHelperTest {
    // 测试方法写在这里
}

步骤3:优化OutputStream验证

用ArgumentMatchers.eq()匹配字节数组,避免引用不一致问题:

verify(os, times(1)).write(ArgumentMatchers.eq("{\"data\":\"test\"}".getBytes(StandardCharsets.UTF_8)));

完整修复后的测试代码

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ControllerHelper.class})
public class ControllerHelperTest {

    @Test
    public void testCallApi() throws Exception {
        // 模拟HttpURLConnection
        HttpURLConnection connection = mock(HttpURLConnection.class);
        doNothing().when(connection).setRequestMethod("POST");
        doNothing().when(connection).setDoOutput(true);
        doNothing().when(connection).setRequestProperty("Accept", "application/json");
        doNothing().when(connection).setRequestProperty("Content-Type", "application/json");

        OutputStream os = mock(OutputStream.class);
        when(connection.getOutputStream()).thenReturn(os);

        InputStream is = new ByteArrayInputStream("{\"result\":\"success\"}".getBytes(StandardCharsets.UTF_8));
        when(connection.getInputStream()).thenReturn(is);

        // 模拟URL实例
        URL url = mock(URL.class);
        when(url.openConnection()).thenReturn(connection);
        PowerMockito.whenNew(URL.class).withArguments(ControllerHelper.SERVER_URL).thenReturn(url);

        // 调用目标方法
        String response = (String) ControllerHelper.callApi("{\"data\":\"test\"}");

        // 验证交互逻辑
        verify(url, times(1)).openConnection();
        verify(connection, times(1)).setRequestMethod("POST");
        verify(connection, times(1)).setDoOutput(true);
        verify(connection, times(1)).setRequestProperty("Accept", "application/json");
        verify(connection, times(1)).setRequestProperty("Content-Type", "application/json");
        verify(os, times(1)).write(ArgumentMatchers.eq("{\"data\":\"test\"}".getBytes(StandardCharsets.UTF_8)));
        verify(connection, times(1)).disconnect();

        // 验证返回结果
        assertEquals("{\"result\":\"success\"}", response);
    }
}

额外建议

  • 避免硬编码配置(如serverUrl),可通过配置文件或依赖注入提供,降低测试难度。
  • 考虑使用OkHttp、RestTemplate等更易用的HTTP客户端库替代原生HttpURLConnection,这类库本身提供更好的测试支持,无需依赖PowerMockito。

内容的提问来源于stack exchange,提问作者Anand_Pawar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 22:35:15