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

使用JUnit编写Apache Http方法单元测试遇阻塞问题求助

问题根源

你的测试未隔离外部HTTP依赖,导致发起真实网络请求,可能因连接未释放、请求超时等问题卡住无法退出。单元测试需聚焦业务逻辑,而非调用真实外部服务。

解决方案:用Mockito Mock Apache HttpClient

通过Mock框架模拟HTTP客户端行为,避免真实网络调用。以下是具体实现步骤:

1. 先确保业务类具备可测试性

重构业务类,通过构造器注入HttpClient,方便测试时替换为Mock实例:

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;

public class UserService {
    private final HttpClient httpClient;

    // 构造器注入HttpClient,替代硬编码创建实例
    public UserService(HttpClient httpClient) {
        this.httpClient = httpClient;
    }

    public User getUserById(String userId) throws Exception {
        HttpGet request = new HttpGet("https://api.example.com/users/" + userId);
        HttpResponse response = httpClient.execute(request);
        String jsonResponse = EntityUtils.toString(response.getEntity());
        return parseJsonToUser(jsonResponse);
    }

    private User parseJsonToUser(String json) {
        // 此处替换为实际JSON解析逻辑(如Jackson/Gson)
        return new User(json.split(":")[1].replace("}", ""));
    }
}

class User {
    private String id;

    public User(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }
}

2. 添加测试依赖(Maven示例)

<!-- JUnit 5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>

3. 编写单元测试

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @Mock
    private HttpClient httpClient; // 创建Mock的HttpClient实例

    @InjectMocks
    private UserService userService; // 自动将Mock注入业务类

    @Test
    void getUserById_ShouldReturnValidUser_WhenHttpResponseIsSuccess() throws Exception {
        // 1. 准备模拟响应数据
        String mockUserJson = "{\"id\":\"123\"}";
        HttpResponse mockResponse = org.mockito.Mockito.mock(HttpResponse.class);
        StringEntity responseEntity = new StringEntity(mockUserJson);

        // 2. 设置Mock行为:调用execute时返回预设响应
        when(mockResponse.getEntity()).thenReturn(responseEntity);
        when(mockResponse.getStatusLine().getStatusCode()).thenReturn(HttpStatus.SC_OK);
        when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse);

        // 3. 执行测试方法
        User result = userService.getUserById("123");

        // 4. 验证结果
        assertEquals("123", result.getId());
    }
}
关键说明
  • 依赖注入:通过构造器传入HttpClient,是实现可测试代码的核心,避免硬编码创建外部依赖。
  • Mock隔离:完全模拟HTTP响应,测试仅验证业务逻辑(如参数拼接、JSON解析),不依赖外部服务或网络。
  • 避免真实请求:Mock后的HttpClient.execute不会发起真实网络调用,自然不会出现端口占用、线程挂起的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 16:12:23