1

I am using mockito to mock a RestTemplate exchange call. Following is what I've used, but it's not picking up the mocked RestTemplate.

Mocked call.

ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class, userId);

The mocked RestTempate as follows.

Mockito.when(restTemplate.exchange(
            Matchers.anyString(),
            Matchers.any(HttpMethod.class),
            Matchers.<HttpEntity<?>> any(),
            Matchers.<Class<String>> any(),
            Matchers.anyString())).
            thenReturn(responseEntity);

Any idea what went wrong here? This runs with @RunWith(PowerMockRunner.class) Since I am mocking a static content.

Aruna Karunarathna
  • 981
  • 2
  • 23
  • 55

3 Answers3

4

The signature has Object... as last param, so you have to use anyVarArg(). This is working fine here:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static org.assertj.core.api.Assertions.assertThat;

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

    @Test
    public void testXXX() throws Exception {
        Mockito.when(this.restTemplate.exchange(Matchers.anyString(), Matchers.any(HttpMethod.class), Matchers.any(), Matchers.<Class<String>>any(), Matchers.<Object>anyVararg()))
               .thenReturn(ResponseEntity.ok("foo"));

        final Bar bar = new Bar(this.restTemplate);
        assertThat(bar.foobar()).isEqualTo("foo");
    }

    class Bar {
        private final RestTemplate restTemplate;

        Bar(final RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
        }

        public String foobar() {
            final ResponseEntity<String> exchange = this.restTemplate.exchange("ffi", HttpMethod.GET, HttpEntity.EMPTY, String.class, 1, 2, 3);
            return exchange.getBody();
        }
    }
}

Note: the use of anyVarArg, a cast (Object) Matches.anyVarArgs() is also possible to avoid the ambiguous method error.

  • Seems like I found the issue, I am creating a new RestTemplate object inside the method,( inside the foobar method in your case). So it won't bind with the mocked RestTemplate object and executing via the actual path. – Aruna Karunarathna May 22 '17 at 11:26
  • @user180100 If I had @ Value "${baseurl:}") private String baseUrl; inside Bar, will creating new Bar() make all local variables null? – Angelina Dec 23 '19 at 14:01
2

I was struggling with the same issue. Here is a mock that worked for me.

 when(this.restTemplate.exchange(anyString(),
            any(),
            any(),
            eq(String.class),
            anyString()))
            .thenReturn(new ResponseEntity<>(subscriptionDataJson,
                    HttpStatus.OK));

Note that I use the varargs as anyString().

Coen Damen
  • 2,009
  • 5
  • 29
  • 51
1

Since I am doing the following in my method. The mocked exchange method is not binding.

RestTempate restTempalte = new RestTemplate();

So I change my source code to the following, and create a method to create a RestTempate instance.

public RestTemplate createRestTemplate() {
    return new RestTemplate();
}

And did the following in the test source.

@Before
public void createMyClass() {
    MockitoAnnotations.initMocks(this);

    sampleClient = new SampleClient() { 
        @Override
        public RestTemplate createRestTemplate() {
            return restTemplate;
        }
    };
}
Aruna Karunarathna
  • 981
  • 2
  • 23
  • 55