我一直在尝试模拟 Java 11 的 HttpClient 但遇到了麻烦。这是我到目前为止所拥有的:
public class ApiPokerTest {
HttpClient client = mock(HttpClient.class);
@Test
public void poking_api_returns_list_of_modules() throws Exception {
HttpResponse<String> resp = mock(HttpResponse.class);
when(resp.body()).thenReturn("Hello world");
when(client.send(any(), any())).thenReturn(resp);
}
}
这不起作用,因为 any() 与 HttpResponse 类型不匹配。我想要的只是当客户端调用 send() 时,它会返回带有给定 JSON 的模拟响应。我该怎么做?
使用mockito
@Spy
@ExtendWith(MockitoExtension.class) // using junit5
@Mock
HttpResponse<InputStream> mockResponse;
@Spy
HttpClient httpClient;
void test() throws Exception {
when(httpClient.send(any(), any(HttpResponse.BodyHandlers.ofInputStream().getClass())))
.thenReturn(mockResponse);
// ...
}
Mockito
无法开箱即用地模拟 final
类(HttpClientImpl 就是这样的类)。使用 Spock
及其 MockingApi
。使用这个测试框架,您可以编写如下测试用例:
given:
def client = Mock(HttpClient)
when:
def response = Mock(HttpResponse)
def responseBody = { 'Hello world' } as Supplier<String>
1 * response.body() >> responseBody
1 * client.send(_ as HttpRequest, _ as HttpResponse.BodyHandler) >> response
def mockedResponseBody = client.send(HttpRequest.newBuilder()
.uri(new URI('http://localhost:8080'))
.build(), HttpResponse.BodyHandlers.discarding()).body()
then:
mockedResponseBody.get() == responseBody.get()
如果您坚持使用 Mockito,则必须在
mocito-extensions
中添加 test\resources
目录,其中包含 org.mockito.plugins.MockMaker
文件,其中包含行 mock-maker-inline
。
出于某种原因,我花了一个多小时才弄清楚,并在 Stack Overflow 上尝试了各种解决方案。最后@ezer的回答帮助了我,我什至不必使用@Spy。
我只是嘲笑这两件事:
@ExtendWith(MockitoExtension.class)
public class MyTest {
@Mock HttpResponse<String> response;
@Mock HttpClient httpClient;
...
我确保
sendAsync
返回模拟的响应:
when(httpClient.sendAsync(any(), any(HttpResponse.BodyHandlers.ofString().getClass())))
.thenReturn(CompletableFuture.completedFuture(response));
最后让模拟的响应返回我想要的。我只关心身体:
when(response.body()).thenReturn("A mocked response!");
我认为我缺少的钥匙是
HttpResponse.BodyHandlers.ofString().getClass()
。之前,我一直收到错误,因为 sendAsync
的第二个参数是泛型 T。我认为指定类可以解决泛型参数问题。