I tried to write test cases for the rest calls in my service which is calling the 3rd party api.
@RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
private ForceService forceService;
@Mock
private ForceServiceConfig config;
@Mock
private RestTemplate restTemplate;
@Before
public void setup() {
forceService = new ForceService(config);
}
@Test
public void apiCall_valid() throws JSONException {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"id=null",
headers);
config.authTokenUrl = "https://ex...com/..";
Mockito.when(restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity, Access.class)).thenReturn(null);
// Mockito.when(any()).thenReturn(null);
forceService.apiCall();
}
}
@Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate();
public ForceService(ForceServiceConfig config) {
this.config = config;
}
private String apiCall() {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"&id=" + config.id,
headers);
ResponseEntity<Access> response = restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity,
Access.class);
return response.getBody().token_type + " " + response.getBody().access_token;
}
}
I get the following error:
org.springframework.web.client.HttpClientErrorException: 404 Not Found at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
It is calling the api in test class, which I do not want to happen. I need to mock the resttemplate call of 3rd party api. How can I do it without being actually calling the api?
This is the problem
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate(); // HERE
you are creating new REAL rest template. What you probably want is to
A don't know is that your actualy structure (1 file 2 classes) but it is safe to assume it is not and in any case you can simply pass RestTemplate as ctor argument. So
@Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config,RestTemplate restTemplate) {
this.restTemplate=restTemplate;
this.config = config;
}
and
@Before
public void setup() {
forceService = new ForceService(config,restTemplate);
}
Now if you want to RestTemplate to be just a stub that does literally nothing and return null on any calls if not instructed otherwiser - leave it as @Mock
.
If you want however, to allow it to work normally and only intercept some specific method calls and stub responses, use spy.
@Mock
private RestTemplate restTemplate;
private RestTemplate restTemplate=Mockito.mock(RestTemplate.class)
or
private RestTemplate restTemplate=Mockito.spy(new RestTemplate());