1

What is the proper way of mocking external API call inside my RestController. Meaning my RestController actually does these steps:

  1. transformation on date
  2. call external API with the data
  3. respond with the external API response

Can't copy/paste because of security issues but in general:

@RestController
public Class x{
RestTemplate y = new RestTemplate();

@RequestMapping(value="/someurl" , method=RequestMethod=POST)
public String myMethod(@RequestBody JsonNode myjson)
{
  //business logic
  ResponseEntity<String> response = restTemplate.exchange(url,HttpMethod,
                                          internalRequest,String.class);
  return response.getBody()
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
user1450410
  • 191
  • 1
  • 13

2 Answers2

1

Here you are creating a new instance of RestTemplate. You can consider defining a bean of RestTemplate in a Configuration class and autowire it here to mock and test it using Mockito framework.

Then the code in the controller must look something like below.

@RestController
public Class Controller{

   @Autowired
   RestTemplate restTemplate;

The RestTemplate bean should be defined in configuration class as below

@Configuration
public class Config {

  @Bean
  public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
  }
} 

Once the above is done you can mock the RestTemplate as below

@RunWith(MockitoJUnitRunner.class)
public class ControllerTest {

  @Mock
  RestTemplate restTemplate;

  @InjectMocks
  Controller controller;

  @Test
  public void myMethodTest() {
     Mockito.when(restTemplate.exchange(Mockito.eq(your url), 
                 Mockito.eq(HttpMethod.your method), Mockito.<HttpEntity<your request 
                 class>> any(), Mockito.<Class<your response class>> 
                 any())).thenReturn(your response entity);
     String response = controller.myMethod(your request);
     Assert.assertThat(response, CoreMatchers.is((your response entity).getBody));
  }

Using the above you can assert the response from the mocked restTemplate.

  • i have 2 issues with that - one is that the : @Autowired RestTemplate restTemplate; have an error of :"could not autowire. no beans of 'RestTemplate'..." the other is how to call myController.myMethod the way you described, since it is a REST API , not a regular method. and how will it work , mockito is changing the external call in the middle of my API with the returned value i give to it in the Mockito.when()... line ? – user1450410 Apr 03 '19 at 15:11
  • Did you define your RestTemplate bean in a @Configuration class? you can call myController.myMethod as the myController is mocked by injecting the RestTemplate mock. When the "myMethod" is call the mocked restTemplate will be invoked and you will receive the output you are returning in "thenReturn" – subhashreddy22 Apr 03 '19 at 16:16
0

I have always used Wiremock for more complex stubbing in my integration tests.

This is a library that you can add as a dependency and let's you stub any specified endpoint (even external) in your test context.

Example stub from the project docs:

stubFor(get(urlEqualTo("/my/resource"))
            .withHeader("Accept", equalTo("text/xml"))
            .willReturn(aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "text/xml")
                .withBody("<response>Some content</response>")));
Smajl
  • 7,555
  • 29
  • 108
  • 179