Faiyet
Faiyet

Reputation: 5471

Mockito JUnit test for simple api call

I consider myself a novice at unit-testing, completely new to Mockito and junit. I have to write unit-tests for some simple api-calls. But my test seems somewhat pointless to me, I can't tell where I am going wrong. I have added a method to an existing web-service, ManagerWS.java , See Below.

ManagerWS.java Method:

public String healthCheck(String userId) { 
    String healthCheckUrlEndpoint  = this.baseUrl()+"/health";
    logger.debug("Calling health check: {}", healthCheckUrlEndpoint);
    HttpHeaders healthCheckHeaders = new HttpHeaders();
    healthCheckHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
    healthCheckHeaders.add(USER_KEY, userId);
    healthCheckHeaders.add(TOKEN_NAME, TOKEN_VALUE);
    healthCheckHeaders.add(Constants.ACCEPT_LANGUAGE_HEADER, LocaleContextHolder.getLocale().toString());
    healthCheckHeaders.add(CORRELATION_HEADER, myService.get(AppLoggingMDCService.LOG_KEY_REQUEST_ID));
    HttpEntity<Object> request = new HttpEntity<Object>(healthCheckHeaders);
    ResponseEntity<String> response;        
    try {
        response = makeRequest(HttpMethod.GET, healthCheckUrlEndpoint, request, String.class); 
    } catch (Exception e) {
        logger.error("Exception encountered during health check", e);
        throw e;
    }       
    logger.debug("RESPONSE : http status: {} - body: {}", response.getStatusCode(), response.getBody());
    return response.getStatusCode().toString();
}

The logic is simple. Construct the url, create headers and add headers to the request. make the request and extract the status-code from the response. Here is my test. NOTE: the class is using @RunWith(SpringRunner.class) and I am using @Mock for dependencies and @InjectMocks for the local instance ManagerWS. ManagerWS.java is the service calss being tested.

TEST-CLASS TEST-Method:

    @Test
    public void testHealthCheck() throws Exception {
    //Given
    managerWS = new ManagerWS(templateFactory, configParamService, mdcService, env);    
    String url = "http://baseurl/health";
    HttpHeaders headers = new HttpHeaders();    
    HttpEntity<Object> request = new HttpEntity<Object>(headers);   
    ResponseEntity<String> response = new ResponseEntity<>(HttpStatus.OK);
    //when
    when(managerWS.makeRequest(HttpMethod.GET, url, request, String.class)).thenReturn(response);
    String actualStatus = response.getStatusCode().toString();  
    //then
    Assert.assertEquals("200",actualStatus);
}

To me this test seems stupid (for want of a batter word). I basicall set the status to give a "200" and assert that what i set is "200". That is not really making much sense.To me it literally does nothing. I tried using spy(ManagerWS.class). But I am literally grasping at straws without the full understanding.

SonarQube still complains with "Not covered by unit tests". I cam completely stumped as to how else to write this test. I also have to do similar tests for three other calls.

I am a total novice to testing and I cannot see my mistake. Please advise.

Upvotes: 1

Views: 4513

Answers (1)

davidxxx
davidxxx

Reputation: 131456

SonarQube still complains with "Not covered by unit tests".

Your unit test doesn't test from the entry point of the method to test : healthCheck(String), so it is not covered by unit tests. Besides, you also mock the part of the method that you want to test :

when(managerWS.makeRequest(HttpMethod.GET, url, request, String.class)).thenReturn(response);

So indeed your approach looks wrong.
In fact, writing an unit test for this code looks wrong too or at least looks like a white box test with few value.
Why ? Your logic depends on :

response = makeRequest(HttpMethod.GET, healthCheckUrlEndpoint, request, String.class); 

But you can know if it works only at runtime, with a running HTTP Server. So the single thing that you can do is mocking everything, spying the object under test and verifying that each statement in the implementation is performed : no readable test, no robust and few/no value.

Your method that relies essentially on side effect would make more sense to be tested with as an integration test :

  ManagerWS managerWS; // real ManagerWS implementation without mock

  @Test
  public void healthCheck() throws Exception {
    //Given
    String url = "http://baseurl/health";
    // When
    String actual managerWS.healthCheck(url);
    // Then
    String expected = "...";
    Assertions.assertEquals(expected, actual);
  }

As a side note, if you used Spring, I would advise you to look at test slicing @WebMvcTest that focuses on the web part of the component under test. It allows mainly to test the HTTP part/logic (headers, request, response).

Upvotes: 1

Related Questions