Search code examples
spring-bootjunitmockingmockitoresttemplate

Using @InjectMock giving URI not absolute error


I have written following Junit for the method which is using rest template to call another service but the mocking is throwing URI not absolute error.

Method:

@Value("${app.prop.esso-url}")
private String essoUrl;

public  ResponseEntity<String> essoCall(String token) {

    ResponseEntity<String> response=null;
    RestTemplate restTemplate = new RestTemplate();

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
    headers.setBearerAuth(token);

    HttpEntity<String> entity = new HttpEntity<>(headers);
    response= restTemplate.exchange(essoUrl, HttpMethod.GET, entity,String.class);

    logger.info("successfully received response.");
    return response;
}

Junit:

@Autowired
private ObjectMapper objectMapper;

@InjectMocks
SecurityMsServiceImpl securityservice=new SecurityMsServiceImpl();



@Value("${app.prop.esso-url}")
private String essoUrl;

@Mock
private RestTemplate restTemplate;


@Test
    void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() {
    ResponseEntity<String> responseEntity = new ResponseEntity<String>("success", HttpStatus.OK);
    Mockito
        .when(restTemplate.getForEntity(essoUrl
        , String.class))
        .thenReturn(responseEntity);

    ResponseEntity<String> finalresponse=securityservice.essoCall("abc");
    assertEquals(responseEntity, finalresponse);
}

Solution

  • I see this problem time and time again:

    You are constructing new instance of RestTemplate in your method under test. What you should do instead is to inject it into your bean, which means:

    • add a field of type RestTemplate in your bean
    • initialize it in constructor
    • in tests, pass in mocked instance
    • in prod, pass in a regular instance via Spring DI

    RestTemplate is thread-safe and one instance of it is perfectly valid. See Is RestTemplate thread safe?

    On top of that:

    • my advice is to use constructor injection instead of field injection
    • you are mixing Spring's @Autowired with Mockito's @InjectMocks. Choose if you want to test with MockitoExtension or SpringExtension and pick the appropriate set of annotations to initialize your SUT.