1

Context

I am completely new to Java / JUinit and I have some trouble understanding how to mock the following API response. In this Extractor class, I have a method getManagers (later to be used as a factory method to return List<Manager>)

public class Extractor {
    ....
    public String getManagers(HashMap parametters, String base_url, String token) throws IOException, InterruptedException {

        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
        HttpRequest request = HttpRequest
                .newBuilder(URI.create(String.format("%s/api/rest/query/HUB_REFERENTIALS/Employee/GD%s", base_url, assembleSemQL(parametters))))
                .header("API-Key", token).GET().build();

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

        return response.body();
}

To get more familiar with Mockito, I started with a trivial test. The point is to be able to write tests execution of which should not depend on the REST API being actually called. testGetManagers check that getManagers returns the same json body as the one loaded from, apiResponse1.json (I checked that apiResponse1.json is properly loaded)

@ExtendWith(MockitoExtension.class)
public class ExtractorTest {
    Extractor extractor = new Extractor();

    @Mock
    HttpClient client;
    HttpResponse response;
    HttpRequest httpRequest;

    @Test
    public void testGetManagers() throws IOException, InterruptedException {

        HashMap<String, String> parametters = new HashMap<String, String>();
        parametters.put("SrcGender", "F");
        // Here        
        Mockito.when(response.body()).thenReturn(Resources.toString(Resources.getResource("apiResponse1.json"), Charsets.UTF_8));

        String response = extractor.getManagers(parametters);
        .....

Issue

It looks like I failed to properly mock response.body(), for I end up with

java.lang.NullPointerException
    at com.comecompany.cockpit.ExtractorTest.testGetManagers(ExtractorTest.java:55)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
....

I think that the problem comes from what I include in @Mock (tried several combinaisons). I probably mis-transposed the logic of how I handle these cases in pytest to org.mockito.Mockito. When I only include HttpResponse response; in @Mock, I get a org.mockito.exceptions.misusing.UnnecessaryStubbingException I do not entirely understand.

What should I include in @Mock to inject this Json file when response.body() is called? Should I mock 'one degree before' (response or HttpResponse<String> response)?

Environnement

  • openjdk11
  • mockito-junit-jupiter 2.23.0
  • junit-jupiter-api 5.7.0
zar3bski
  • 2,773
  • 7
  • 25
  • 58

1 Answers1

1

You need to put @Mock annotation before each field

@Mock
HttpClient client;
@Mock
HttpResponse response;
@Mock
HttpRequest httpRequest;
Morph21
  • 1,111
  • 6
  • 18
  • It solves the exception issue but `response.body()` does not seem mocked -- i.e. it seems that I get responses from the actual API rather than `apiResponse1.json` – zar3bski Jan 11 '21 at 13:01
  • if you are calling the actual API you will get response from it. You need to do something like here https://stackoverflow.com/questions/25564533/how-to-mock-remote-rest-api-in-unit-test-with-spring – Morph21 Jan 11 '21 at 13:22
  • I though that `org.mockito.Mockito` works like patches (like python's `MagikMock`). I was probably wrong – zar3bski Jan 11 '21 at 14:56
  • I'm attempting something similar but I'm mocking `client.send(request, HttpResponse.BodyHandlers.ofString());` so I can return the actual result with all my desired response info; 201 status, body, headers etc. BUT, I can't mock the result because it requires a CompletableFuture and I haven't managed to create an object properly for it. – Tony Feb 08 '21 at 13:24