How do I mock a REST template exchange?

155,244

Solution 1

You don't need MockRestServiceServer object. The annotation is @InjectMocks not @Inject. Below is an example code that should work

@RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {
    @Mock
    private RestTemplate restTemplate;

    @InjectMocks
    private SomeService underTest;

    @Test
    public void testGetObjectAList() {
        ObjectA myobjectA = new ObjectA();
        //define the entity you want the exchange to return
        ResponseEntity<List<ObjectA>> myEntity = new ResponseEntity<List<ObjectA>>(HttpStatus.ACCEPTED);
        Mockito.when(restTemplate.exchange(
            Matchers.eq("/objects/get-objectA"),
            Matchers.eq(HttpMethod.POST),
            Matchers.<HttpEntity<List<ObjectA>>>any(),
            Matchers.<ParameterizedTypeReference<List<ObjectA>>>any())
        ).thenReturn(myEntity);

        List<ObjectA> res = underTest.getListofObjectsA();
        Assert.assertEquals(myobjectA, res.get(0));
    }

Solution 2

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);

Solution 3

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);

Solution 4

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);

Solution 5

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);
Share:
155,244

Related videos on Youtube

Akka Jaworek
Author by

Akka Jaworek

i code

Updated on July 09, 2022

Comments

  • Akka Jaworek
    Akka Jaworek almost 2 years

    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?

    • Akka Jaworek
      Akka Jaworek over 7 years
      anyone has an idea?
  • Martin Schröder
    Martin Schröder almost 6 years
    Doesn't work with org.hamcrest.Matchers and org.mockito.Matchers is deprecated in favor of hamcrest.
  • bpedroso
    bpedroso almost 6 years
    You can use it with generic matcher too. ArgumentMatchers.<Class<?>>any())
  • Roeland Van Heddegem
    Roeland Van Heddegem over 5 years
    "Matchers" is deprecated and should be replaced with "ArgumentMatchers" because of a name clash. Class Matchers
  • Angelina
    Angelina almost 5 years
    How do we add contents to the myEntity.getBody()? Mine comes back null
  • Sham Fiorin
    Sham Fiorin almost 5 years
    Matchers are deprecated, you should use Mockito
  • Mindaugas
    Mindaugas almost 5 years
    @Angelina since it's a real object just use an appropriate constructor i.e ResponseEntity(T body, HttpStatus status)
  • Marino
    Marino over 4 years
    @Mindaugas I´ve used the constructor but my response still is null ResponseEntity<String> response = new ResponseEntity<>( "a string",HttpStatus.OK );
  • Mindaugas
    Mindaugas over 4 years
    @Marino make sure that your mocked method that is supposed to return the response entity is being called and that it is infact configured to return said entity
  • Marino
    Marino over 4 years
    I´m sorry, @Mindaugas but still doesn´t works! My test code is ResponseEntity<String> responseEntity = new ResponseEntity<>("sampleBodyString", HttpStatus.CREATED); doReturn(responseEntity).when(restTemplate).exchange(anyStri‌​ng(), any(HttpMethod.class), any(HttpEntity.class), eq(String.class)); TokenBean tokenBeanResult = tokenService.refresh("refresh-token"); and my real code is: ResponseEntity<String> response = restTemplate.exchange(tokenApiConfig.getUrl(), HttpMethod.POST, request, String.class); and response is still null
  • Mindaugas
    Mindaugas over 4 years
    @Marino is request parameter of type HttpEntity.class? cause that is what you are using to mock the rest template call
  • G_V
    G_V almost 4 years
    The Matchers class is deprecated now
  • Lanon
    Lanon over 3 years
    @Mock and @InjectMocks were a key in my test case.
  • Skillz
    Skillz about 3 years
    I'm using a regular rest template and this was the only thing that worked
  • electrobabe
    electrobabe over 2 years
    in my case: when(restTemplate.exchange(any(String.class), eq(HttpMethod.GET), any(), eq(new ParameterizedTypeReference<String>() {}))).thenReturn(myEntity);