I have a requirement to unit test a method that makes an external API call using RestTemplate for which I am trying to mock the response of external API and assert the return value of the method. I have also tried to mock the response using MockRestServiceServer
and @InjectMocks
but was unable to get the expected output and it makes the actual API call. Any guidance will be appreciated.
Test Case
public class SnowFlakeServiceTest {
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private final SnowFlakeServiceImpl snowFlakeService = new SnowFlakeServiceImpl(restTemplate);
@Test
public void testGetAccessToken() {
SnowFlakeTokenDTO snowFlakeTokenDTO = new SnowFlakeTokenDTO();
snowFlakeTokenDTO.setAccessToken("fakeAccessToken");
snowFlakeTokenDTO.setExpiresIn(600);
snowFlakeTokenDTO.setTokenType("Bearer");
ResponseEntity<SnowFlakeTokenDTO> responseEntity = new ResponseEntity<>(snowFlakeTokenDTO, HttpStatus.OK);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<SnowFlakeTokenDTO>>any()))
.thenReturn(responseEntity);
assertThat(snowFlakeService.getAccessToken()).isEqualTo(snowFlakeTokenDTO.getAccessToken());
}
}
SnowFlakeServiceImpl.java
private final RestTemplate restTemplate;
public SnowFlakeServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public String getAccessToken() {
log.debug("token requested id : {}, secret :{}", snowFlakeClientId, snowFlakeClientSecret);
try {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
httpHeaders.setBasicAuth(snowFlakeClientId, snowFlakeClientSecret);
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("grant_type", snowFlakeRefreshTokenGrantType);
requestBody.add("refresh_token", refreshToken);
requestBody.add("redirect_uri", snowFlakeRedirectUrl);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestBody, httpHeaders);
ResponseEntity<SnowFlakeTokenDTO> response = restTemplate.exchange(snowFlakeTokenRequestUrl, HttpMethod.POST, request, SnowFlakeTokenDTO.class);
log.debug("response: {}", response);
return Objects.requireNonNull(response.getBody()).getAccessToken();
} catch (Exception e) {
log.debug("error: {}", ExceptionUtils.getRootCauseMessage(e));
throw new ErrorDTO(Status.BAD_REQUEST, accessTokenErrorMessage, e.getMessage());
}
}
RestTemplateConigurations.java
@Configuration
public class RestTemplateConfiguration {
@Value("${rest-template.connection.timeout}")
private int connectionTimeout;
@Value("${rest-template.read.timeout}")
private int readTimeout;
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofMillis(connectionTimeout))
.setReadTimeout(Duration.ofMillis(readTimeout))
.build();
}
}
Spring Boot : 2.5.4
Java : 11
Junit : 5
CodePudding user response:
You don't need a new RestTemplate
every time you call the getAccessToken()
method. It should instead be injected by Spring:
@Service
public class SnowFlakeService {
private RestTemplate restTemplate;
public ServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public String getAccessToken() {
try {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
httpHeaders.setBasicAuth(snowFlakeClientId, snowFlakeClientSecret);
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("grant_type", snowFlakeRefreshTokenGrantType);
requestBody.add("refresh_token", refreshToken);
requestBody.add("redirect_uri", snowFlakeRedirectUrl);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestBody, httpHeaders);
ResponseEntity<SnowFlakeTokenDTO> response = restTemplate.exchange(snowFlakeTokenRequestUrl, HttpMethod.POST, request, SnowFlakeTokenDTO.class);
return Objects.requireNonNull(response.getBody()).getAccessToken();
} catch (Exception e) {
throw new ErrorDTO(Status.BAD_REQUEST, accessTokenErrorMessage, e.getMessage());
}
}
}
On top of this, you don't actually need a @SpringBootTest
in order to test SnowFlakeService
. A regular unit test is pretty much ok.
public class SnowFlakeServiceTest {
private RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private SnowFlakeService snowFlakeService = new SnowFlakeService(restTemplate);
@Test
public void testGetAccessToken() {
SnowFlakeTokenDTO snowFlakeTokenDTO = new SnowFlakeTokenDTO();
snowFlakeTokenDTO.setAccessToken("fakeAccessToken");
snowFlakeTokenDTO.setExpiresIn(600);
snowFlakeTokenDTO.setTokenType("Bearer");
ResponseEntity<SnowFlakeTokenDTO> responseEntity = new ResponseEntity<>(snowFlakeTokenDTO, HttpStatus.OK);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<SnowFlakeTokenDTO>>any()))
.thenReturn(responseEntity);
assertThat(snowFlakeService.getAccessToken()).isEqualTo(snowFlakeTokenDTO.getAccessToken());
}
}