使用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
相关产品推荐
相关产品推荐

