We have code that executes RestTemplate.exchange() to execute an HTTP request, and a Unit Test that tests it. The expected params (5) are
@Override
public <T> ResponseEntity<T> exchange(String url,
HttpMethod method,
@Nullable HttpEntity<?> requestEntity,
Class<T> responseType,
Object... uriVariables)
throws RestClientException {
The code line to be mocked is below (note the last varargs is omitted, which is OK):
responseEntity = restTemplate.exchange(endpointUrl,
HttpMethod.POST,
requestEntity,
responseType);
Originally in Spring 3.0.2 the following Mockito line mocked the right conditions for us in our unit test:
MockedConstruction<RestTemplate> mockRC = Mockito.mockConstruction(RestTemplate.class,
(mock, context) -> {
when(mock.exchange(Mockito.anyString(),
Mockito.any(HttpMethod.class),
Mockito.any(HttpEntity.class),
Mockito.any(Class.class),
Mockito.any(Object.class)
)).thenThrow(new HttpClientErrorException(HttpStatus.UNPROCESSABLE_ENTITY));
But then after we upgraded to Spring 3.3.2 it no longer mocks correctly. My suspicion is that last varargs param is handled in some new way. Any thoughts?
This is a breaking change in Mockito 5 how varargs arguments are handled by matchers.
Spring Boot 3.0.2 pulled Mockito 4.8.1 while Spring Boot 3.1.0+ pulls at least Mockito 5.3.1 (Mockito 5.11.0 for current Spring Boot 3.3.2).
It's also documented in the JavaDoc of the ArgumentMatchers#any(Class)
method:
Notes :
- For primitive types use
anyChar()
family.- Since Mockito 2.1.0 this method will perform a type check thus null values are not authorized.
- Since Mockito 2.1.0
any()
is no longer an alias of this method.- Since Mockito 5.0.0 this method can match varargs if the array type is specified, for example
any(String[].class)
.
So you will need to change your stub to either of the following:
Match no varargs (empty varargs array) passed – will match your specific call exactly:
when(mock.exchange(Mockito.anyString(),
Mockito.any(HttpMethod.class),
Mockito.any(HttpEntity.class),
Mockito.any(Class.class)))
Match any number of varargs passed – will match any call to the exchange
method:
when(mock.exchange(Mockito.anyString(),
Mockito.any(HttpMethod.class),
Mockito.any(HttpEntity.class),
Mockito.any(Class.class),
Mockito.any(Object[].class)))