Forumpy
Forumpy

Reputation: 335

Mocking Java 11 HttpClient?

I've been trying to mock Java 11's HttpClient but I've been having trouble. This is what I have so far:

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);
}

}

This doesn't work because any() doesn't match HttpResponse type. All I want is when the client calls send() it returns a mocked response with given JSON. How can I do this?

Upvotes: 1

Views: 3744

Answers (3)

Andrew Cheong
Andrew Cheong

Reputation: 30273

For some reason this took me over an hour to figure out, trying all sorts of solutions on Stack Overflow. In the end @ezer's answer helped me, and I didn't even have to use @Spy.

I simply mocked these 2 things:


@ExtendWith(MockitoExtension.class)
public class MyTest {

  @Mock HttpResponse<String> response;
  @Mock HttpClient httpClient;

  ...

And I made sure sendAsync returns the mocked response:


when(httpClient.sendAsync(any(), any(HttpResponse.BodyHandlers.ofString().getClass())))
    .thenReturn(CompletableFuture.completedFuture(response));

And finally made the mocked response return what I wanted. I only cared about the body:

when(response.body()).thenReturn("A mocked response!");

I think the key I was missing was the HttpResponse.BodyHandlers.ofString().getClass(). Before, I kept getting errors because the second parameter of sendAsync is a generic, T. I think specifying the class that way resolved the generic parameter issue.

Upvotes: 1

ezer
ezer

Reputation: 1172

use 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);
  // ...
}

Upvotes: 1

Bananan
Bananan

Reputation: 609

Mockito can't mock final classes (HttpClientImpl is such class) out of the box. Use Spock and its MockingApi. With this testing framework you can write test case like this:

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()

If you insist using Mockito you have to add mocito-extensions directory in test\resources with org.mockito.plugins.MockMaker file with line mock-maker-inline inside.

Upvotes: 0

Related Questions