How to stub HttpClient send method in mockito

791 Views Asked by At

I am calling an external API using HttpClient as below,

   HttpClient client = HttpClient.newHttpClient();
   HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/api"))
                    .POST(BodyPublishers.ofString(requestBody)).header("Authorization", 
                           authorizationHeader)
                    .header("Content-Type", "application/json").build();

   HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
   LOGGER.debug(response.body());

I have tried solution from How to mock HttpClient's send method in junit 5?. This actually does not have information on how to return the expected response in stubbing statement.

I am basically looking to stub below statement so that I can test the expected and actual result without invoking the real API,

    client.send(request, HttpResponse.BodyHandlers.ofString()); 

The real API call returns a json in String format, which I will then be mapping to an entity and use it further.

Could someone please put your thoughts on this. Thanks in advance.

3

There are 3 best solutions below

2
tgdavies On BEST ANSWER

The problem with your test is that as the HttpClient instance is created inside the method you are testing, you can't mock it. You need to change your code to be something like the code below.

You would probably want to extend the test to make some more assertions about the parameters passed to send, and to test your handling of the response (which isn't shown in your question), but I think this answer explains how to mock the client successfully.

package com.example.demo;

import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.net.URI;
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.*;

class MyClass {
    private final HttpClientFactory httpClientFactory;

    MyClass(HttpClientFactory httpClientFactory) {
        this.httpClientFactory = httpClientFactory;
    }

    public HttpResponse<String> myMethod(String requestBody) throws IOException, InterruptedException {

        HttpClient client = httpClientFactory.create();
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/api"))
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .header("Content-Type", "application/json").build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        return response;
    }
}

class HttpClientFactory {
    public HttpClient create() {
        return HttpClient.newHttpClient();
    }
}

public class MyTest {


    @Test
    public void aTest() throws IOException, InterruptedException {
        HttpClientFactory mockFactory = mock(HttpClientFactory.class);
        HttpClient mockClient = mock(HttpClient.class);
        HttpResponse mockResponse = mock(HttpResponse.class);
        when(mockFactory.create()).thenReturn(mockClient);
        when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
                .thenReturn(mockResponse);
        MyClass classToTest = new MyClass(mockFactory);
        classToTest.myMethod("the request body");
        verify(mockClient).send(argThat(request -> request.uri().equals(URI.create("http://localhost:8080/api"))), any());
    }
}


2
Feel free On

You can try to do it like:

when(client.send(request, HttpResponse.BodyHandlers.ofString()).thenReturn(response)

or

 when(client.send(any(), anyString()).thenReturn(response)

The response could be the mock object or you can create response whatever you want for it

and then you can test assertEquals((expectedResult, yourmethod())

0
SherOFF On

I am calling an external API using HttpClient as below,

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/api"))
    .POST(BodyPublishers.ofString(requestBody)).header("Authorization", 
                           authorizationHeader)
    .header("Content-Type", "application/json").build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());