如何使用Spock框架Mock java.net.http.HttpClient?
解决方案:Mock java.net.http.HttpClient 的 send 调用(无需重构代码)
问题背景
现有静态方法提供HttpClient实例:
@CompileStatic private static HttpClient getClient() { return HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(5)) .build() }
业务代码中通过该实例调用第三方API:
final HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString())
无法重构代码,尝试GroovySpy(global: true)、GroovyMock(global: true)(包括针对HttpClientImpl)均无效,且因依赖过多无法重写getClient()方法,需要Mock指定返回值。
可行方案:使用PowerMock + Mockito 静态Mock
由于目标是Mock静态方法HttpClient.newBuilder()的链式调用,从而控制返回的HttpClient实例,进而Mock其send方法,步骤如下:
- 引入依赖
确保测试依赖中包含PowerMock和Mockito的适配包(以Gradle为例):
testImplementation "org.powermock:powermock-module-junit4:2.0.9" testImplementation "org.powermock:powermock-api-mockito2:2.0.9" testImplementation "org.mockito:mockito-core:3.12.4"
- 编写测试代码
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; @RunWith(PowerMockRunner.class) @PrepareForTest(HttpClient.class) // 标记需要Mock的静态类 public class YourServiceTest { @Mock private HttpClient mockHttpClient; @Mock private HttpClient.Builder mockBuilder; @Mock private HttpResponse<String> mockResponse; @Test public void testApiCall() throws Exception { // 1. Mock HttpClient.newBuilder() 返回我们的mockBuilder mockStatic(HttpClient.class); when(HttpClient.newBuilder()).thenReturn(mockBuilder); // 2. 链式Mock Builder的配置方法,最终返回mockHttpClient when(mockBuilder.version(any(HttpClient.Version.class))).thenReturn(mockBuilder); when(mockBuilder.connectTimeout(any())).thenReturn(mockBuilder); when(mockBuilder.build()).thenReturn(mockHttpClient); // 3. Mock send方法的返回值 when(mockResponse.body()).thenReturn("Mocked API Response"); when(mockHttpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))) .thenReturn(mockResponse); // 执行你的业务方法,此时会使用我们Mock的HttpClient YourService.yourBusinessMethod(); // 验证逻辑(可选) // verify(mockHttpClient).send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)); } }
关键说明
- PowerMock允许Mock静态方法、私有方法等Mockito无法覆盖的场景,正好适配
HttpClient.newBuilder()这种静态创建实例的场景。 - 通过链式Mock Builder的每一步调用,确保最终返回我们创建的Mock HttpClient实例,这样后续的
send调用就能被我们控制。 - 无需修改原有业务代码,完全通过测试框架实现Mock。
内容的提问来源于stack exchange,提问作者john
相关产品推荐
相关产品推荐

