Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito "thenThrow" doesn't throw the exception when expected

I have an issue when trying to test a class that represents a Rest Client. I'm using RestTemplate in Spring Boot.

This is the abstract RestClient class:

    public abstract class RestClient {
    ...

    public RestResponse sendPostRequest(URI baseUri, String resource, IRestRequest restRequest, ClassresponseClass)
            throws ServerException, ClientException {

        ...

        try {

            RestTemplate restTemplate = new RestTemplate();
            response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
            result = response.getBody();

            getLogger().debug("[{}] received", result);
            return result;
        } catch (HttpClientErrorException e) {
            throw new ClientException(e.getCause());
        } catch (HttpServerErrorException e) {
            throw new ServerException(e.getCause());
        } catch (Exception e) {
            getLogger().error("Error with cause: {}.", e.getMessage());
        }

        ...
    }
}

This is the actual implementation:

    public class ActualRestClient extends RestClient {

    public RestResponse sendFetchFileRequest(URI baseUri, FetchFileRequest request) throws ServerException, ClientException {
        return sendPostRequest(baseUri, "FETCH_FILE", request, RestResponse.class);
    }
 }

An this is the test:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ActualRestClient.class, RestClient.class})
public class ActualResRestClientTest {

private static final String REQUEST_URI = "something";

@InjectMocks
public ActualRestClient testee;

@Mock
private RestTemplate restTemplate;


@Test(expected = ServerException.class)
public void sendPostRequestWithResponseBody_throwsServerException() throws Exception {

    HttpServerErrorException httpServerErrorException = new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR);
    when(restTemplate.exchange(Mockito.any(URI.class), eq(HttpMethod.POST), Mockito.any(), eq(FetchFileRequest.class))).thenThrow(httpServerErrorException);

    testee.sendFetchFileRequest(new URI(REQUEST_URI), new FetchFileRequest());
 }
}

ClientException and ServerException are exceptions created by me by extending Exception class. My problem is that in the RestClient class another Exception is catched(message:"URI is not absolute") instead of HttpServerErrorException and I can't understand why. Thank you!

like image 729
B. Bal Avatar asked Apr 21 '26 08:04

B. Bal


1 Answers

As the commenter already expressed: doing new URI("something") already throws at you. But even when you pass a "valid" URI, your code will not work, as there is a misconception on your end. You see:

RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);

That code lives within a method of your class under test. But @InjectMocks works only for fields of classes.

In other words: when your production code gets executed, a new (completely different** ResponseTemplate instance is created. And therefore your mocking spec is irrelevant, because the method isn't invoked on your mock in the first place.

Two choices:

  • turn that local variable into a field of your class under test (then injecting should work)
  • or, as you are already using PowerMock(ito), you could use that mocking framework to intercept that call to new().

I suggest you rather use option one, and avoid to use the PowerMock(ito) extension altogether!

like image 151
GhostCat Avatar answered Apr 22 '26 22:04

GhostCat



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!