Hot questions for Using Mockito in resttemplate

Top 10 Java Open Source / Mockito / resttemplate

Question:

public class ServiceTest {
    @Mock
    RestTemplate restTemplate = new RestTemplate();
    @InjectMocks
    Service service = new Service();
    ResponseEntity responseEntity = mock(ResponseEntity.class);

    @Test
    public void test() throws Exception {
        Mockito.when(restTemplate.getForEntity(
                Mockito.anyString(),
                Matchers.any(Class.class)
                ))
                .thenReturn(responseEntity);
        boolean res = service.isEnabled("something");
        Assert.assertEquals(res, false);
    }

I tried to test a simple test for a service including a restclient. It looks I have not Mock the RestTemplate successfully. It looks like the code get the real data not the mock one. Anyone can help me with this.

The service itself will looks as this:

public class Service{
    public boolean isEnabled(String xxx) {
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}

Answer:

The problem is that in your isEnabled you are creating a new RestTemplate. This is wrong for two reasons, one is that you cannot mock it since you are creating a new one, and second it is good to avoid creating new objects per request. RestTemplate is thread safe and hence can be a service class member, being used across many threads.

Change your service class to something like this:

public class Service{

    RestTemplate restTemplate = new RestTemplate();

    public boolean isEnabled(String xxx) {
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}

Now that your RestTemplate has become a class member you can now properly mock through one of two ways. One, inject it using the @InjectMock, or use a setter method that you call from your test.

Since you are using InjectMock in your code we can go with that.

@RunWith(MockitoJUnitRunner.class) 
public class ServiceTest {
    @Mock
    RestTemplate restTemplate;
    @InjectMocks
    @Spy
    Service service;
    ResponseEntity responseEntity = mock(ResponseEntity.class);

    @Test
    public void test() throws Exception {
        Mockito.when(restTemplate.getForEntity(
                Mockito.anyString(),
                ArgumentMatchers.any(Class.class)
                ))
                .thenReturn(responseEntity);
        boolean res = service.isEnabled("something");
        Assert.assertEquals(res, false);
    }

Notice that I made a few changes. First, I removed the new RestTemplate() and new Service(). You should let mockito create those for you. By annotating them with @Mock and @Spy you will ensure that Mockito will create them for you, and more importantly, will inject the mocks into your service object.

Question:

I have a service class, written in spring, with some methods. One of this acts as a restful consumer like below:

.....
        HttpEntity request = new HttpEntity<>(getHeadersForRequest());
        RestTemplate restTemplate = new RestTemplate();
        String url = ENDPOINT_URL.concat(ENDPOINT_API1);

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
                .queryParam("param1", parameter1);
        ReportModel infoModel = null;
        try{
            infoModel = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, request, ReportModel.class).getBody();
        }catch (HttpClientErrorException | HttpServerErrorException e){
            e.printStackTrace();
        }

I want to use Mockito to mock my service, but every method that interacts with restful server instance a new RestTemplate. I've to create a static class to Inject it into my service?


Answer:

One of the benefits from dependency injection is to be able to easily mock your dependencies. In your case it would be a lot easier to create a RestTemplate bean:

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

And in stead of using new RestTemplate() in your client you should use:

@Autowired
private RestTemplate restTemplate;

For the unit testing with Mockito you'll have to mock the RestTemplate, for example by using:

@RunWith(MockitoJUnitRunner.class)
public class ClientTest {
    @InjectMocks
    private Client client;
    @Mock
    private RestTemplate restTemplate;
}

In this case Mockito will mock and inject the RestTemplate bean in your Client. If you don't like mocking and injecting through reflection you can always go for a separate constructor or setter to inject the RestTemplate mock.

Now you can write a test like this:

client.doStuff();
verify(restTemplate).exchange(anyString(), eq(HttpMethod.GET), any(HttpModel.class), eq(ReportModel.class));

You'll probably want to test more than that, but it gives you a basic idea.

Question:

My service class code is as below:

public class MyServiceImpl implements MegatillAccessService {
@Autowired
RestTemplate restTemplate;

@Value("${api.key}")
private String apiKey;

@Value("${customers.url}")
private String postUrl;

@Override
public String pushCustomerData(List<Customer> listOfcustomers, String storeId) throws MyServiceException {

Set<Customer> setOfCustomers = new HashSet<>(listOfcustomers);
    int noOfCustomersLoadedSuccessfully =0;

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
    headers.add("apiKey", apiKey);
    headers.add("Content-Type", "application/json");
    headers.add("storeId", storeId);
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

    for(Customer customer: setOfCustomers){
        HttpEntity<Customer> request = new HttpEntity<Customer>(customer, headers);
        CustomerDataDto customerDataDto = null;
        try {
            customerDataDto = restTemplate.exchange(postUrl, HttpMethod.POST, request, CustomerDataDto.class).getBody();
        }
        catch (HttpClientErrorException ex) {
            if (ex.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
                log.error("The customers service is not available to load data: "+ ex.getResponseBodyAsString(), ex);
                throw new MyServiceException("The customers service is not available to load data",new RuntimeException(ex));
            }
            else{
                log.warn("Error for customer with alias: "+customer.getAlias() +" with message: "+ ex.getResponseBodyAsString(), ex);
                if(!ex.getResponseBodyAsString().contains("already found for this shop")){
                    throw new MyServiceException("An error occurred while calling the customers service with status code "+ex.getStatusCode(),new RuntimeException(ex));
                }
            }
        }
        catch(Exception e){
            throw new MyServiceException("An error occurred while calling the customers service: ",new RuntimeException(e));
        }

        if(null != customerDataDto) {
            noOfCustomersLoadedSuccessfully++;
            log.debug("--------Data posted successfully for: ---------"+customerDataDto.getAlias());
        }
    }
    String messageToReturn = "No. of unique customers from source: "+setOfCustomers.size()+". No. of customers loaded to destination without error: "+noOfCustomersLoadedSuccessfully;
    return messageToReturn;
}
}

My Test class is as below:

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class MyServiceTest {

@InjectMocks
private MyService myService = new MyServiceImpl();

@Mock
RestTemplate restTemplate;

@Before
public void setUp() throws Exception
{
    MockitoAnnotations.initMocks(this);
    initliaizeModel();
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
}

@Test
public void pushAllRecords(){

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

    /*Mockito.when(restTemplate.exchange(Mockito.anyString(),
            Mockito.<HttpMethod> eq(HttpMethod.POST),
            Matchers.<HttpEntity<?>> any(),
            Mockito.<Class<CustomerDataDto>> any()).getBody()).thenReturn(customerDataDto);*/

    String resultReturned = myService.pushCustomerData(customers,"1235");
    assertEquals(resultReturned, "No. of unique customers from source: 2. No. of customers loaded to destination without error: 2");
}

}

While running the test, I am getting NullPointerException at the line where I am giving the Mockito.when and thenReturn condition. I tried many combinations but it is still giving NPE. I can't even reach the method invocation.Can you please let me know where am I going wrong?


Answer:

You get NullPointerException because you are doing too much in your Mockito.when. Your code inside when (shorter version):

restTemplate.exchange(args).getBody()

You are trying to mock getBody() but it is called on exchange(args). And what does exchange(args) returns? Mockito doesn't know what it should return and you didn't specify that so by default it returns null.

That's why you get NPE.

To fix this you can either do mocking step by step, ie.

ResponseEntity re = Mockito.when(exchange.getBody()).thenReturn(customerDataDto);
Mockito.when(restTemplate.exchange()).thenReturn(re);

or specify mock to return deep stubs, like that (if you want to use annotations):

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
RestTemplate restTemplate;

Question:

Can't figure out the correct way to use matchers to identify which overload of the exchange method I am targetting. The call I am making:

restTemplate.exchange(url, HttpMethod.PUT, httpEntity, Object.class)

I've tried using any(Class.class), and a couple other things but nothing is working. There are 2 methods with a similar signature that I am trying to distinguish between:

exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType)

and

exchange(String var1, HttpMethod var2, @Nullable HttpEntity<?> var3, ParameterizedTypeReference<T> var4)

Here are my current imports related to Mockito:

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

Has anyone been able to mock a call to this method that uses a Class as the 4th parameter instead of a ParameterizedTypeReference?


Answer:

I am not sure whether I misunderstood your question or the issue mentioned by @MarciejKowalski, but when running the test from the issue or what I suppose is similar to your example against mockito-core-2.23.4 / JDK 1.8.0_151 it works just fine.

[I used JUnit 4 for your example instead of JUnit 5]

import static org.mockito.ArgumentMatchers.any;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {

    @Test
    public void test() {

        RestTemplate api = Mockito.mock(RestTemplate.class);
        ResponseEntity<?> response1 = Mockito.mock(ResponseEntity.class);
        ResponseEntity<?> response2 = Mockito.mock(ResponseEntity.class);

        Mockito.when(api.exchange(any(String.class), any(HttpMethod.class), any(HttpEntity.class), any(Class.class))).thenReturn(response1);
        Mockito.when(api.exchange(any(String.class), any(HttpMethod.class), any(HttpEntity.class), any(ParameterizedTypeReference.class))).thenReturn(response2);

        ParameterizedTypeReference mock = Mockito.mock(ParameterizedTypeReference.class);

        Assert.assertEquals(response1, api.exchange("", HttpMethod.GET, new HttpEntity(""), String.class));
        Assert.assertEquals(response2, api.exchange("", HttpMethod.GET, new HttpEntity(""), mock));
    }
}

Question:

I am trying to mock this service that calls an API using rest template and returns a List.

I am unable to mock the restTemplate.exchange() method. It's giving me a "java.lang.IllegalArgumentException: URI is not absolute" exception.

edit- My stupid self forgot to put http:// before the base url in the test case and that is why I was getting that. Thanks for helping and apologies for wasting your time.

Method to be tested

@Value("${base-url}")
private String baseUrl;

@Override
public List<Currency> getCurrencyList() {
    RestTemplate restTemplate = new RestTemplate();
    String url = baseUrl + "/currency";
    ResponseEntity<List<Currency>> result;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity<String> dataHttpEntity = new HttpEntity<>(headers);
    log.info(url);
    result = restTemplate.exchange(url, HttpMethod.GET,dataHttpEntity, new ParameterizedTypeReference<List<Currency>>() {
    });
    return result.getBody();
}

The Testing code

@Test
public void getCurrencyListTest() {
   ResponseEntity<List<Currency>> result = ResponseEntity.ok(currencyList);

    when(restTemplate.exchange( ArgumentMatchers.anyString(),
            ArgumentMatchers.any(HttpMethod.class),
            ArgumentMatchers.any(),
            ArgumentMatchers.<Class<List<Currency>>>any())).thenReturn(result);
     assertEquals(currencyList,service.getCurrencyList());
}

Exception

java.lang.IllegalArgumentException: URI is not absolute

at java.net.URI.toURL(URI.java:1088)
at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:145)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:87)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:721)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:682)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:627)
at com.fpts.seller.service.external.impl.DocumentServiceImpl.getCurrencyList(DocumentServiceImpl.java:34)
at com.fpts.seller.service.external.DocumentServiceImplTest.getCurrencyListTest(DocumentServiceImplTest.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:78)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:84)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:161)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Answer:

Give a protocol name for your baseUrl and try again please, i mean by protocol is : http or https .

For example:

String url = "http://" + baseUrl + "/currency";

Question:

I have a method:

public void putObj(Doc doc) {
        for (int i = 0; i < 3; i++) {
            try {
                OAuth2RestTemplate restTemplate = something.thatReturnsOAuth2RestTemplate(props);
                restTemplate.postForEntity(somethingElse.getUrl(), doc.toJSONString(), String.class);
                break;
            } catch (HttpClientErrorException | HttpServerErrorException e) {
                //do stuff in here
            }
        }
    }

And my test class:

@RunWith(MockitoJUnitRunner.class)
@PrepareForTest(OkHttp3TemplateUtil.class)
public class TestingClass {

@InjectMocks
private static MyService myService;

@Mock
private static Something something;

@Mock
private static Props props;

@Mock
private static OAuth2RestTemplate restTemplate;

@Test
    public void testExceptionCaughtWhenThrownByRestTemplate(){
        PowerMockito.mockStatic(OkHttp3TemplateUtil.class);
        Doc doc = new Doc.docBuilder().setSomething("");

        when(something.thatReturnsOAuth2RestTemplate(props)).thenReturn(restTemplate);
        when(restTemplate.postForEntity("http://dummy.com", String.class, String.class)).thenThrow(HttpClientErrorException.class);
        myService.putObj(doc);
    }
}

No matter what I do, thenThrow never throws an exception. The test passes never providing coverage for code after catch. What am I missing here, I'm going mad!


Answer:

It looks like you need to use matchers from Mockito.

In your case the 3 args for restTemplate are a bit confusing. The 1st is a String value so use anyString() to match it and mock out somethingElse.getUrl(), that code isn't in the example so not sure what it does but it must return a String and not be null. It looks like you want to match any string for the 2nd, with Mockito you need to use anyString() or any() if it is not a String to accomplish that. The 3rd is the actual value of String.class so again use eq(). Note, if any params are null it will not match. Also, it is easy to end up mocking out a different overloaded postForEntity if you're not careful.

For the something.thatReturnsOAuth2RestTemplate, you might be OK without a matcher. If the Props class has equals defined and both the test and production code values are equal. However, the example doesn't show this info, so I just added the any(Props.class) for that too.

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;

@Test
    public void testExceptionCaughtWhenThrownByRestTemplate(){
        PowerMockito.mockStatic(OkHttp3TemplateUtil.class);
        Doc doc = new Doc.docBuilder().setSomething("");

                when(something.thatReturnsOAuth2RestTemplate(any(Props.class))).thenReturn(restTemplate);
        when(restTemplate.postForEntity(anyString(), any(), eq(String.class))).thenReturn(response);
}

Question:

I am currently writing unit test for below method

@Autowired
private RequestConfig requestConfig;

@Autowired
private RetryTemplate retryTemplate;

public ResponseEntity<String> makeGetServiceCall(String serviceUrl) throws Exception {
    try {
        return retryTemplate.execute(retryContext -> {

            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = requestConfig.createHttpHeaders();
            HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
            ResponseEntity<String> response = restTemplate.exchange(serviceUrl, HttpMethod.GET, entity, String.class);
            return response;

        });
    } catch (Exception e) {
        throw new Exception("Generic exception while makeGetServiceCall due to" + e + serviceUrl);
    }
}

UPDATED METHOD:

@Autowired
private RequestConfig requestConfig;

@Autowired
private RetryTemplate retryTemplate;

@Autowired
private RestTemplate restTemplate;

public ResponseEntity<String> makeGetServiceCall(String serviceUrl) throws Exception {
    try {
        return retryTemplate.execute(retryContext -> {

            HttpHeaders headers = requestConfig.createHttpHeaders();
            HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
            ResponseEntity<String> response = restTemplate.exchange(serviceUrl, HttpMethod.GET, entity, String.class);
            return response;

        });
    } catch (Exception e) {
        throw new Exception("Generic exception while makeGetServiceCall due to" + e + serviceUrl);
    }
}

I tried all possibilities but I am unable to get it right. Here is my below test.

@Mock
private RestTemplate restTemplate;

@Mock
public RequestConfig requestConfig;

@InjectMocks
private RetryTemplate retryTemplate;

ServiceRequest serviceRequest;


@Test
public void makeGetServiceCall() throws Exception {
    String url = "http://localhost:8080";
    RetryTemplate mockRetryTemplate = Mockito.mock(RetryTemplate.class);
    RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
    ResponseEntity<String> myEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
    Mockito.when(mockRetryTemplate.execute(ArgumentMatchers.any(RetryCallback.class), ArgumentMatchers.any(RecoveryCallback.class), ArgumentMatchers.any(RetryState.class))).thenReturn(myEntity);

    Mockito.when(mockRestTemplate.exchange(
            ArgumentMatchers.eq(url),
            ArgumentMatchers.eq(HttpMethod.GET),
            ArgumentMatchers.<HttpEntity<String>>any(),
            ArgumentMatchers.<Class<String>>any())
    ).thenReturn(myEntity);

    ResponseEntity<String> response = serviceRequest.makeGetServiceCall(url);
    Assert.assertEquals(myEntity, response);
}

UPDATED TEST CASE:

 @Mock
public RequestConfig requestConfig;

@Mock
private RestTemplate restTemplate;

@Mock
private RetryTemplate retryTemplate;

@InjectMocks
ServiceRequest serviceRequest;

@Test
public void makeGetServiceCall() throws Exception {
    //given:
    String url = "http://localhost:8080";

    when(requestConfig.createHttpHeaders()).thenReturn(null);
    ResponseEntity<String> myEntity = new ResponseEntity<>( HttpStatus.ACCEPTED);
    when(retryTemplate.execute(any(RetryCallback.class), any(RecoveryCallback.class), any(RetryState.class))).thenAnswer(invocation -> {
        RetryCallback retry = invocation.getArgument(0);
        return retry.doWithRetry(/*here goes RetryContext but it's ignored in ServiceRequest*/null);
    });
    when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), eq(String.class)))
            .thenReturn(myEntity);

    //when:
    ResponseEntity<String> response = serviceRequest.makeGetServiceCall(url);

    //then:
    assertEquals(myEntity, response);
}

The response object which I get from my method call makeGetServiceCall always return null. When I debug the code I see exception org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ResponseEntity cannot be returned by toString() toString() should return String error on the resttemplate mocking where I return myEntity

I am not sure what am I missing.


Answer:

Well, you have made quite some number of mistakes...

  1. I'm sure you wanted to annotate private RetryTemplate retryTemplate; with @Mock, not @InjectMocks
  2. @InjectMocks should go onto ServiceRequest serviceRequest;
  3. You are defining interactions on some mockRetryTemplate and mockRestTemplate which have nothing to do with serviceRequest. Instead, you should use your @Mock-annotated fields to define interactions on because they are being injected into your object under test (serviceRequest)
  4. Moreover, you can't normally mock RestTemplate and inject it into your ServiceRequest because you don't use dependency injection in the first place for RestTemplate in ServiceRequest. You just instantiate its instance in ServiceRequest.makeGetServiceCall
  5. You are defining an interaction on the wrong method at line Mockito.when(retryTemplate.execute(.... Your interaction specifies RetryTemplate.execute(RetryCallback, RecoveryCallback, RetryState) whereas your ServiceRequest uses another method RetryTemplate.execute(RetryCallback)
  6. You should also notice that RetryTemplate.execute is final and so you can't mock it without extra efforts as explained here. And generally, you should prefer interfaces over classes, e.g. RestOperations and RetryOperations over RestTemplate and RetryTemplate respectively, to be more flexible.

That said, below is the working test which solves your problem. But take note of removing RestTemplate restTemplate = new RestTemplate(); from ServiceRequest and making restTemplate a field so it's dependency-injected.

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

    @Mock
    public RequestConfig requestConfig;

    @Mock
    private RetryTemplate retryTemplate;

    @InjectMocks
    ServiceRequest serviceRequest;

    @Test
    public void makeGetServiceCall() throws Exception {
        //given:
        String url = "http://localhost:8080";
        ResponseEntity<String> myEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
        when(retryTemplate.execute(any(RetryCallback.class))).thenAnswer(invocation -> {
            RetryCallback retry = invocation.getArgument(0);
            return retry.doWithRetry(/*here goes RetryContext but it's ignored in ServiceRequest*/null);
        });
        when(restTemplate.exchange(eq(url), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class)))
                .thenReturn(myEntity);

        //when:
        ResponseEntity<String> response = serviceRequest.makeGetServiceCall(url);

        //then:
        assertEquals(myEntity, response);
    }
}

Question:

I'm trying to mock a rest template in my DAO class but Mockito throws weird error saying it isn't able to mock.

Trying to cover unit test cases for my Spring boot app version 2.x. I have almost tried all possible solutions over the internet like updating JDK/JRE for compilation but I'm stuck with the following error:

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class org.springframework.web.client.RestTemplate.

Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.


Java               : 1.8
JVM vendor name    : Oracle Corporation
JVM vendor version : 25.181-b13
JVM name           : Java HotSpot(TM) 64-Bit Server VM
JVM version        : 1.8.0_181-b13
JVM info           : mixed mode
OS name            : Windows 10
OS version         : 10.0


Underlying exception : java.lang.IllegalArgumentException: Could not create type
    at org.mockito.junit.jupiter.MockitoExtension.beforeEach(MockitoExtension.java:115)
....

Following is my code:

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
    implementation 'org.springframework.retry:spring-retry'
    implementation 'org.aspectj:aspectjrt'
    implementation 'org.aspectj:aspectjweaver'
    implementation 'org.springframework:spring-aop'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.2.0'
    testCompile 'org.junit.jupiter:junit-jupiter-params:5.2.0'
    testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.2.0'
    testImplementation 'org.mockito:mockito-core:2.+'
    testImplementation 'org.mockito:mockito-junit-jupiter:2.18.3'
}

test {
    testLogging.showStandardStreams = true
    useJUnitPlatform()
}

MyDao.java

@Repository
public class MyDao {    
    @Value("${app.prop.service.url}")
    private String url;

    @Autowired
    public RestTemplate restTemplate;

    public String getSignals() {
        System.out.println("url -----------------------> " + url);
        return new RetryTemplate().execute(context -> {
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);

            if (response.getStatusCodeValue() == 200) {
                System.out.println("Server response -> " + response.getBody());
                return response.getBody();
            } else {
                throw new RuntimeException("server response status: " + response.getStatusCode());
            }
        }, context -> {
            System.out.println("retry count: " + context.getRetryCount());
            System.err.println("error -> " + context.getLastThrowable());
            return null;
        });
    }
}

MyDaoTest.java

@ExtendWith(MockitoExtension.class)
public class MyDaoTest {    
    @Mock
    private RestTemplate restTemplate;

    @InjectMocks
    private MyDao dao;

    @BeforeEach
    public void prepare() {
        ResponseEntity<String> response = new ResponseEntity<>("{name: myname}", HttpStatus.OK);
        Mockito.doReturn(response).when(restTemplate.getForEntity(Mockito.anyString(), String.class));
    }

    @Test
    public void testGetSignals() {
        System.out.println("------------------TEST-------------------");
        String result = dao.getSignals();
        System.out.println("result ------>" + result);
        assertEquals("{name: myname}", result);
    }
}

BeanConfig for RestTemplate

@Bean
public RestTemplate restTemplate() {
    // block of code for SSL config for HTTPS connection
    return new RestTemplate();
}

Any suggestions will be really helpful

P.S: The application is running perfectly fine through gradle command

gradlew bootRun

The problem is only with unit testing

gradlew test

Answer:

One cause of the described (or a subordinate) problem might be, since RestTemplate is nor "private" nor "final" and "known as mockable", the invocation/mocking of restTemplate.getForEntity()

... in the current version, this method is available in three flavors/with overloading parameters:

  • ... getForEntity(String url, Class<T> responseType, Object... uriVariables) ...
  • ... getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) ...
  • ... getForEntity(URI url, Class<T> responseType) ...

In your (operative) code you seem to use the 1st flavor, so without changing it (the operative code), I propose to adjust your test code to:

...restTemplate.getForEntity(Mockito.anyString(), String.class
/*!!!*/, ArgumentMatchers.<Object>any());

See also:

  • Mockito not working for RestTemplate
  • How to properly match varargs in Mockito

But the error message still makes me "cautious" & wondering... you are on the "beeding edge" junit (5) stack, are you confident regarding your test setup!? (missing gradle libs/config?)

Please, "try":

testCompile "org.mockito:mockito-core:2.+"
testCompile('org.mockito:mockito-junit-jupiter:2.18.3')

not:

...
testImplementation 'org.mockito:mockito-core:2.+'
testImplementation 'org.mockito:mockito-junit-jupiter:2.18.3'

..as shown at dzone's spring-boot-2-with-junit-5-and-mockito-2-for-unit. If that (and other findings from the tutorial) doesn't help, consider to really:

report (it) to the mailing list(.)


And i heard/read the first time (in my life):

mock a rest template in my DAO class

Consider to name your dao as "service" (+ the according steps/refactorings;)

Question:

I have the following code that is inside of a method that I am testing. I need to mock this restTemplate call to get predictable result.

GitHubEmail[] gitHubEmails = restTemplate
        .getForObject(userEmailsUrl, GitHubEmail[].class, oAuthToken);

In the test method, I do this:

RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);

GitHubEmail fakeGitHubEmail = new GitHubEmail("testemail@email.com", 
                                 false, false, GitHubEmailVisibility.PRIVATE);
    GitHubEmail[] fakeEmails = {fakeGitHubEmail};

    Mockito.when(mockRestTemplate.getForObject(
                     Mockito.eq(userUrl), 
                     Mockito.eq(GitHubEmail[].class),
                     Mockito.eq(testOAuthToken)))
           .thenReturn(fakeEmails);

    gitHubService.setRestTemplate(mockRestTemplate);
    User user = gitHubService.getUser(testOAuthToken);

Things aren't working as I expect them to... When I examine gitHubEmails variable in my method I am testing, it's null.

Why isn't this working?


Answer:

The current code as it is right now does not contain any mistakes. However, there are two things we don't see from the given code:

  1. We don't see that testOAuthToken is properly passed to the oAuthToken variable within the githubService.
  2. We don't see that the userUrl is passed to the userEmailsUrl within githubService.

You should make sure that all properties match the one you expect them to be, otherwise the mocking doesn't work. Given that you named one property userUrl and the other one userEmailsUrl, it's likely that the error is there.

Usually, when I encounter these error-prone mocking situations, I use "any matchers" (any(), anyString(), ...) when mocking and then after the call and the assertions, I use Mockito.verify() to check if the parameters match:

Mockito.when(mockRestTemplate.getForObject(
        Mockito.anyString(), // Use anyString()
        Mockito.eq(GitHubEmail[].class),
        Mockito.anyString())) // Use anyString()
    .thenReturn(fakeEmails);

// Call + Assertions ...

Mockito.verify(mockRestTemplate).getForObject(
    Mockito.eq(userUrl), // Use eq()
    Mockito.eq(GitHubEmail[].class),
    Mockito.eq(testOAuthToken)); // Use eq()

The reason for this is that the verify() output gives a lot more feedback. Rather than just failing, it will tell why it failed when:

  • The mocked method was called with different arguments, and which arguments
  • The mocked object had different methods being invoked

Question:

I have a service method with restTemplate. As part of unit test, I am trying to mock it but some how failing.

Service Method:

@Autowired
private RestTemplate getRestTemplate;

return getRestTemplate.getForObject(restDiagnosisGetUrl, SfdcCustomerResponseType.class);

Test Method:

private CaresToSfdcResponseConverter caresToSfdcResponseConverter;

    @Before
    public void setUp() throws Exception {
        caresToSfdcResponseConverter = new CaresToSfdcResponseConverter();

    }
    @Test
    public void testConvert(){
    RestTemplate mock = Mockito.mock(RestTemplate.class);
         Mockito.when(mock.getForObject(Matchers.anyString(), Matchers.eq(SfdcCustomerResponseType.class))).thenReturn(sfdcCustomerResponseType);
}
sfdcRequest = caresToSfdcResponseConverter.convert(responseForSfdcAndHybris);

It is giving NullPointerException. Looks like it is failing to mock rest template and it is breaking there as rest template is null. Any help would appreciated.Thanks


Answer:

It's not failing to mock the rest template, but it's not injecting the mocked rest template to your production class. There are at least two ways to fix this.

You can change your production code and use constructor injection. Move the RestTemplate to the constructor as a parameter and then you can just pass the mock in the test:

@Service
public class MyService {
    @Autowired
    public MyService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
}

In your test you will simply create the service as any other object and pass it your mocked rest template.

Or you can change your test to inject your service using the following annotation:

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
    @InjectMocks
    private MyService myService;

    @Mock
    private RestTemplate restTemplate;

    @Test
    public void testConvert(){
         Mockito.when(mock.getForObject(Matchers.anyString(), Matchers.eq(SfdcCustomerResponseType.class))).thenReturn(sfdcCustomerResponseType);
    }
}

You can see an example in another SO question: Using @Mock and @InjectMocks

I generally prefer constructor injection.

Question:

I am trying to unit test the following Spring boot code with RestTemplate sending a request to the API and retrieving some resources from it:

final URI targetUri = UriComponentsBuilder.fromUriString(baseUri)
                .path("/myEntities").build().toUri();

final RequestEntity<Void> request = RequestEntity.get(targetUri).accept(HAL_JSON).build();
final Resources<MyEntity> resourceAccounts = restTemplate.exchange(request, new ResourcesType<MyEntity>() {
        }).getBody();

In the unit test, I am mocking this request-response using Mockito:

final Resources<MyEntity> myEntities = new Resources<>(myEntityList, links);
final ResponseEntity<Object> response = new ResponseEntity<Object>(myEntities, HttpStatus.OK);

when(restTemplate.exchange(any(RequestEntity.class), any(ResourcesType.class))).thenReturn(response);

It works fine but I am getting Unchecked invocation exchanged because I am not using the generics correctly.

I just wonder what is the correct and bullet-proof way of doing this? I tried casting the ResponseEntity type to MyEntity but this does causes compile exception (the constructor ResponseEntity<MyEntity> is undefined).


Answer:

With type safe method of Matchers ? One of the way to check method invocations with the generics.

Matchers.<ResponseType<MyEntity>>.any()

Source - Reference

To check the response of a method, ArgumentCaptor can be used.

Question:

I am trying to mock a call to RestTemplate.exchange() but cant get it to work. Currently the call to exchange() hangs so I believe the actual method is being called instead of my mock. The call to exchange() is as follows:

ResponseEntity<List<MyType>> response = 
    restTemplate.exchange(queryStr, 
                   HttpMethod.GET, 
                   null,
                   new ParameterizedTypeReference<List<MyType>>() {
                   });

The mocking is as follows:

@MockBean
private RestTemplate restTemplate;

@Test
public void testMethod() throws Exception {

    when(restTemplate.exchange(anyString(),
                eq(HttpMethod.GET),
                eq(null),
                eq(new ParameterizedTypeReference<List<MyType>>(){})
    )).thenReturn(new ResponseEntity<List<MyType>>(HttpStatus.OK));

    // rest of test code follows.

}

I have tried changing the argument matchers around so they match a broader argument types (ie. any() in place of anyString()) but I get the same behavior or an error "reference to exchange is ambiguous both method exchange(...) and method exchange(...) match". I also get "no suitable method found for thenReturn(...) is not compatible with thenReturn(...)" along with the first error.

Thanks in advance.


Answer:

Found that we did not annotate the instance of the RestTemplate with @Autowired that was used in our controler.

@RestController
public class myController {

    ...

    @Autowired  // <-- Forgot this annotation.
    private RestTemplate restTemplate;

    ...

}

Now mocks work correctly.

Question:


Answer:

Question:

I have a generic method which invokes specified URL using RestTemplate.exchange. Method itself is working and loading data fine but I am not able to unit test it using Mockito.

Main Method

@Service
public class MyClass{
    private <T> List<T> loadData(String url) {
        return restTemplate.exchange(
            url, GET, null, new ParameterizedTypeReference<List<T>>(){}
        ).getBody().stream().collect(toList()));
    }
}

Unit Test

@Runwith(MockitoJUnitRunner.class)
public class MyTest {
    @Mock
    private RestTemplate restTemplate;

    @Test
    public void givenCall_myMethod_WillReturnData(){
        given(restTemplate.exchange(
            ArgumentMatchers.anyString(), ArgumentMatchers.any(), any(), any(Class.class)
        ))
        .willReturn(bodyData());
    }
}

If I use non-generic version then everything works fine, however mockito returns NullPointerException with generics version.

What's wrong or missing?


Answer:

The last wildcard you have defined as: any(Class.class).

The exchange method has signature:

exchange(String url,
             HttpMethod method,
             HttpEntity<?> requestEntity,
             ParameterizedTypeReference<T> responseType) throws RestClientException

You should define it as: any(ParameterizedTypeReference.class)

Also I would suggest replacing the very vague any() set-us with a any(Class) equivalents.

Question:

I am trying to mock a Rest Client using Mockito which takes in the following:-

MainServiceClass.java

public String serviceCall(String s1){

    String data2 = "s1";

  try{
      headers = new HttpHeaders();
      headers.setContentType(MediaType.APPLICATION_JSON);
      headers.set("headers1", "headers1");

      HttpEntity<String> entity = new HttpEntity<String>(data2, headers);
        ResponseEntity<Object> responseEntity = restTemplate.exchange(someurl, HttpMethod.POST, entity, Object.class);

      return someString; }

ServiceTest.java

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class RestTemplateTests {

 @InjectMocks
    @Spy
    private Someservice service;

    @Autowired
    private MockMvc mockMvc;


        @Mock
        RestTemplate restTemplate;

        ResponseEntity responseEntity = mock(ResponseEntity.class);



    @Test
    public void myCallToTemplate() throws Exception {
    @Test
    public Mytestforcallingservice() {
      Mockito.when(restTemplate.exchange(
                                    someurl,
                                    HttpMethod.POST,
                                    Mockito.<HttpEntity<String>> any(),
                                    Mockito.<Class<?>> 
                                any())).thenReturn(responseEntity);
                    String s2 = service.serviceCall(s1);
                    Assert.assertEquals(s2, "hey");
    }

Below is my Error:-

.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
        Invalid use of argument matchers!
        4 matchers expected, 2 recorded:
        -> at com.example.MyServiceClass.Mytestforcallingservice(ServiceTest.java:110)
        -> at com.example.ServiceTest.Mytestforcallingservice(ServiceTest.java:110)

        This exception may occur if matchers are combined with raw values:
            //incorrect:
            someMethod(anyObject(), "raw String");
        When using matchers, all arguments have to be provided by matchers.
        For example:
            //correct:
            someMethod(anyObject(), eq("String by matcher"));

The Test fails at forming HttpEntity which has both data2 and headers. How can I form that in the Mockito call ?

Also, how can I verify it.

Thank you.


Answer:

Mockito is saying you can't use argument matchers (in your case Mockito.any()) with raw values (in your case "someurl" and HttpMethod.POST) So either you remove your argument matchers or you add an argument matcher to your raw values. Mockito.eq on "someurl" and HttpMethod.POST in your case would trigger the mock in your test. see below.

Also if you want to verify your rest template was invoked in a particular way you can use Mockito.verify(). See below to verify the rest template was invoked with a particular url

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class MyService {
    private String someurl = "myurl";
    private RestTemplate restTemplate = new RestTemplate();

    public String serviceCall(String s1) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("headers1", "headers1");

        HttpEntity<String> entity = new HttpEntity<String>(s1, headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange(someurl, HttpMethod.POST, entity, String.class);

        return responseEntity.getBody();
    }

}

and

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

@RunWith(MockitoJUnitRunner.class)
public class RestTemplateTests {

    @Mock
    private RestTemplate restTemplate;

    private String testUrl = "myurl";
    @InjectMocks
    private MyService serviceClass;

    @Test
    public void test1() {
        String expectedBody = "hey";
        ResponseEntity<String> responseEntity = new ResponseEntity<>(expectedBody, HttpStatus.OK);
        when(restTemplate.exchange(eq(testUrl), eq(HttpMethod.POST), any(), eq(String.class)))
                .thenReturn(responseEntity);
        String s2 = serviceClass.serviceCall("s1");
        verify(restTemplate, times(1)).exchange(eq(testUrl), any(), any(), eq(String.class));
        assertEquals(s2, expectedBody);
    }
}