[java] How do I mock a REST template exchange?

I have a service in which I need to ask an outside server via rest for some information:

public class SomeService {

    public List<ObjectA> getListofObjectsA() {
        List<ObjectA> objectAList = new ArrayList<ObjectA>();
        ParameterizedTypeReference<List<ObjectA>> typeRef = new ParameterizedTypeReference<List<ObjectA>>() {};
        ResponseEntity<List<ObjectA>> responseEntity = restTemplate.exchange("/objects/get-objectA", HttpMethod.POST, new HttpEntity<>(ObjectAList), typeRef);
        return responseEntity.getBody();
    }
}

How can I write a JUnit test for getListofObjectsA()?

I have tried with the below:

@RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {
    private MockRestServiceServer mockServer;

    @Mock
    private RestTemplate restTemplate;

    @Inject
   private SomeService underTest;

@Before
public void setup() {
    mockServer = MockRestServiceServer.createServer(restTemplate);
    underTest = new SomeService(restTemplate);
    mockServer.expect(requestTo("/objects/get-objectA")).andExpect(method(HttpMethod.POST))
            .andRespond(withSuccess("{json list response}", MediaType.APPLICATION_JSON));
}

    @Test
    public void testGetObjectAList() {
    List<ObjectA> res = underTest.getListofObjectsA();
    Assert.assertEquals(myobjectA, res.get(0));
}

However the above code does not work, it shows that responseEntitty is null. How can I correct my test to properly mock restTemplate.exchange?

This question is related to java spring-boot junit mockito

The answer is


I used to get such an error. I found a more reliable solution. I have mentioned the import statements too which have worked for me. The below piece of code perfectly mocks restemplate.

import org.mockito.Matchers;
import static org.mockito.Matchers.any;

    HttpHeaders headers = new Headers();
    headers.setExpires(10000L);     
    ResponseEntity<String> responseEntity = new ResponseEntity<>("dummyString", headers, HttpStatus.OK);
    when(restTemplate.exchange( Matchers.anyString(), 
            Matchers.any(HttpMethod.class),
            Matchers.<HttpEntity<?>> any(), 
            Matchers.<Class<String>> any())).thenReturn(responseEntity);

Let say you have an exchange call like below:

String url = "/zzz/{accountNumber}";

Optional<AccountResponse> accResponse = Optional.ofNullable(accountNumber)
        .map(account -> {


            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.set("Authorization", "bearer 121212");


            HttpEntity<Object> entity = new HttpEntity<>(headers);
            ResponseEntity<AccountResponse> response = template.exchange(
                    url,
                    GET,
                    entity,
                    AccountResponse.class,
                    accountNumber
            );

            return response.getBody();
        });

To mock this in your test case you can use mocitko as below:

when(restTemplate.exchange(
        ArgumentMatchers.anyString(),
        ArgumentMatchers.any(HttpMethod.class),
        ArgumentMatchers.any(),
        ArgumentMatchers.<Class<AccountResponse>>any(),
        ArgumentMatchers.<ParameterizedTypeReference<List<Object>>>any())
)


This work on my side.

ResourceBean resourceBean = initResourceBean();
ResponseEntity<ResourceBean> responseEntity  
    = new ResponseEntity<ResourceBean>(resourceBean, HttpStatus.ACCEPTED);
when(restTemplate.exchange(
    Matchers.anyObject(), 
    Matchers.any(HttpMethod.class),
    Matchers.<HttpEntity> any(), 
    Matchers.<Class<ResourceBean>> any())
 ).thenReturn(responseEntity);

If anyone has this problem while trying to mock restTemplate.exchange(...), the problem seems to be with matchers. As an example: the following won't work,

when(ecocashRestTemplate.exchange(Mockito.any()
                , Mockito.eq(HttpMethod.GET)
                , Mockito.any(HttpEntity.class)
                , Mockito.<Class<UserTransaction>>any())
        ).thenReturn(new ResponseEntity<>(transaction, HttpStatus.OK));

but this one will actually work:

  ResponseEntity<UserTransaction> variable = new ResponseEntity<>(transaction, HttpStatus.OK);
  when(ecocashRestTemplate.exchange(Mockito.anyString()
                , Mockito.eq(HttpMethod.GET)
                , Mockito.any(HttpEntity.class)
                , Mockito.<Class<UserTransaction>>any())
   ).thenReturn(new ResponseEntity<>(transaction, HttpStatus.OK));

NOTICE the Mockito.anyString() on the second block vs theMockito.any().


If anyone is still facing this issue, Captor annotation worked for me

@Captor
private ArgumentCaptor<Object> argumentCaptor;

Then I was able to mock the request by:

ResponseEntity<YourTestResponse> testEntity = new ResponseEntity<>(
    getTestFactoryResponse(), 
    HttpStatus.OK);
when(mockRestTemplate.exchange((String) argumentCaptor.capture(), 
    (HttpMethod) argumentCaptor.capture(), 
    (HttpEntity<?>) argumentCaptor.capture(), 
    (Class<YourTestResponse.class>) any())
).thenReturn(testEntity);

I implemented a small library that is quite useful. It provides a ClientHttpRequestFactory that can receive some context. By doing so, it allows to go through all client layers such as checking that query parameters are valued, headers set, and check that deserialization works well.


If your intention is test the service without care about the rest call, I will suggest to not use any annotation in your unit test to simplify the test.

So, my suggestion is refactor your service to receive the resttemplate using injection constructor. This will facilitate the test. Example:

@Service
class SomeService {
    @AutoWired
    SomeService(TestTemplateObjects restTemplateObjects) {
        this.restTemplateObjects = restTemplateObjects;
    }
}

The RestTemplate as component, to be injected and mocked after:

@Component
public class RestTemplateObjects {

    private final RestTemplate restTemplate;

    public RestTemplateObjects () {
        this.restTemplate = new RestTemplate();
        // you can add extra setup the restTemplate here, like errorHandler or converters
    }

    public RestTemplate getRestTemplate() {
        return restTemplate;
    }
}

And the test:

public void test() {

    when(mockedRestTemplateObject.get).thenReturn(mockRestTemplate);

    //mock restTemplate.exchange
    when(mockRestTemplate.exchange(...)).thenReturn(mockedResponseEntity);

    SomeService someService = new SomeService(mockedRestTemplateObject);
    someService.getListofObjectsA();
}

In this way, you have direct access to mock the rest template by the SomeService constructor.


If you are using RestTemplateBuilder may be the usual thing wouldn't work. You need to add this in your test class along with when(condition).

@Before    
public void setup() {        
     ReflectionTestUtils.setField(service, "restTemplate", restTemplate);    
}

ResponseEntity<String> responseEntity = new ResponseEntity<String>("sampleBodyString", HttpStatus.ACCEPTED);
when(restTemplate.exchange(
                           Matchers.anyString(), 
                           Matchers.any(HttpMethod.class),
                           Matchers.<HttpEntity<?>> any(), 
                           Matchers.<Class<String>> any()
                          )
                         ).thenReturn(responseEntity);

The RestTemplate instance has to be a real object. It should work if you create a real instance of RestTemplate and make it @Spy.

@Spy
private RestTemplate restTemplate = new RestTemplate();

For me, I had to use Matchers.any(URI.class)

Mockito.when(restTemplate.exchange(Matchers.any(URI.class), Matchers.any(HttpMethod.class), Matchers.<HttpEntity<?>> any(), Matchers.<Class<Object>> any())).thenReturn(myEntity);

This is an example with the non deprecated ArgumentMatchers class

when(restTemplate.exchange(
                ArgumentMatchers.anyString(),
                ArgumentMatchers.any(HttpMethod.class),
                ArgumentMatchers.any(),
                ArgumentMatchers.<Class<String>>any()))
             .thenReturn(responseEntity);

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to spring-boot

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Why am I getting Unknown error in line 1 of pom.xml? Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured How to resolve Unable to load authentication plugin 'caching_sha2_password' issue ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName ERROR Source option 1.5 is no longer supported. Use 1.6 or later How to start up spring-boot application via command line? JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value

Examples related to junit

Eclipse No tests found using JUnit 5 caused by NoClassDefFoundError for LauncherFactory How to resolve Unneccessary Stubbing exception JUnit 5: How to assert an exception is thrown? How do I mock a REST template exchange? Class Not Found: Empty Test Suite in IntelliJ Unable to find a @SpringBootConfiguration when doing a JpaTest Failed to load ApplicationContext (with annotation) Example of Mockito's argumentCaptor Mockito - NullpointerException when stubbing Method Spring jUnit Testing properties file

Examples related to mockito

How to resolve Unneccessary Stubbing exception How do I mock a REST template exchange? Mockito : doAnswer Vs thenReturn Example of Mockito's argumentCaptor Mockito: Mock private field initialization Mockito - NullpointerException when stubbing Method Usages of doThrow() doAnswer() doNothing() and doReturn() in mockito Java verify void method calls n times with Mockito Unfinished Stubbing Detected in Mockito How do I mock an autowired @Value field in Spring with Mockito?