Discussion:
Mockito Spring RestTemplate Mocking Problem
dev danke
2013-07-29 23:23:17 UTC
Permalink
I'm having a little trouble with Mockito. I have a RestClient that wraps
Spring's RestTemplate. In a unit test of my RestClient's post() method, I
want to verify that it correctly handles a RestTemplate exception.

The problem is that my unit test doesn't trigger the mocked restTemplate to
throw an exception. I want restTemplate.exchange() to throw an exception,
but instead it just returns null.

Here's the RestClient method I'm testing:

public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}

Here's my unit test:

@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}

Here's the signature of the RestTemplate method I want to throw an
exception:

public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }


Please let me know if you have any ideas on how to make this work.

Thanks,
Dan
Piotr Wyrwinski
2013-07-30 04:18:24 UTC
Permalink
Maybe try creating instances and define your when() with them instead of
just using any(). If I remember correctly you can use eq(), to mix
instances with any() when passing them as arguments. I realize that you
might have to change your implementation to try that, but this is where I
would start troubleshooting this.

hope this helps,

Piotr
Post by dev danke
**
I'm having a little trouble with Mockito. I have a RestClient that wraps
Spring's RestTemplate. In a unit test of my RestClient's post() method, I
want to verify that it correctly handles a RestTemplate exception.
The problem is that my unit test doesn't trigger the mocked restTemplate
to throw an exception. I want restTemplate.exchange() to throw an
exception, but instead it just returns null.
public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}
@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}
Here's the signature of the RestTemplate method I want to throw an
public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }
Please let me know if you have any ideas on how to make this work.
Thanks,
Dan
Keith Hamburg
2013-07-30 05:07:23 UTC
Permalink
You have to use doThrow when the method you're mocking returns null. It
explains it here in the documentation:

http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#12

Stubbing voids requires different approach from
when(Object)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#when(T)>
because
the compiler does not like void methods inside brackets...

doThrow(Throwable)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#doThrow(java.lang.Throwable)>
replaces
the stubVoid(Object)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#stubVoid(T)>
method
for stubbing voids. The main reason is improved readability and consistency
with the family of doAnswer() methods.

Use doThrow() when you want to stub a void method with an exception:

doThrow(new RuntimeException()).when(mockedList).clear();

//following throws RuntimeException:
mockedList.clear();
Post by Piotr Wyrwinski
**
Maybe try creating instances and define your when() with them instead of
just using any(). If I remember correctly you can use eq(), to mix
instances with any() when passing them as arguments. I realize that you
might have to change your implementation to try that, but this is where I
would start troubleshooting this.
hope this helps,
Piotr
Post by dev danke
**
I'm having a little trouble with Mockito. I have a RestClient that wraps
Spring's RestTemplate. In a unit test of my RestClient's post() method, I
want to verify that it correctly handles a RestTemplate exception.
The problem is that my unit test doesn't trigger the mocked restTemplate
to throw an exception. I want restTemplate.exchange() to throw an
exception, but instead it just returns null.
public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}
@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}
Here's the signature of the RestTemplate method I want to throw an
public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }
Please let me know if you have any ideas on how to make this work.
Thanks,
Dan
David Karr
2013-07-30 14:56:38 UTC
Permalink
Keith, you're confusing returning null with void methods. You need
"doThrow()" on a void method, not a method that returns null.
Post by Keith Hamburg
**
You have to use doThrow when the method you're mocking returns null. It
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#12
Stubbing voids requires different approach from when(Object)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#when(T)> because
the compiler does not like void methods inside brackets...
doThrow(Throwable)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#doThrow(java.lang.Throwable)> replaces
the stubVoid(Object)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#stubVoid(T)> method
for stubbing voids. The main reason is improved readability and consistency
with the family of doAnswer() methods.
doThrow(new RuntimeException()).when(mockedList).clear();
mockedList.clear();
Post by Piotr Wyrwinski
**
Maybe try creating instances and define your when() with them instead of
just using any(). If I remember correctly you can use eq(), to mix
instances with any() when passing them as arguments. I realize that you
might have to change your implementation to try that, but this is where I
would start troubleshooting this.
hope this helps,
Piotr
Post by dev danke
**
I'm having a little trouble with Mockito. I have a RestClient that
wraps Spring's RestTemplate. In a unit test of my RestClient's post()
method, I want to verify that it correctly handles a RestTemplate exception.
The problem is that my unit test doesn't trigger the mocked restTemplate
to throw an exception. I want restTemplate.exchange() to throw an
exception, but instead it just returns null.
public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}
@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}
Here's the signature of the RestTemplate method I want to throw an
public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }
Please let me know if you have any ideas on how to make this work.
Thanks,
Dan
dev danke
2013-07-30 17:17:42 UTC
Permalink
Further experimenting showed the cause was the varargs urlVariables
parameter in the RestTemplate exchange() method. I must pass it a non-null
Object for that arg, or the mocked method won't get invoked.
Post by Keith Hamburg
**
You have to use doThrow when the method you're mocking returns null. It
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#12
Stubbing voids requires different approach from when(Object)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#when(T)> because
the compiler does not like void methods inside brackets...
doThrow(Throwable)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#doThrow(java.lang.Throwable)> replaces
the stubVoid(Object)<http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#stubVoid(T)> method
for stubbing voids. The main reason is improved readability and consistency
with the family of doAnswer() methods.
doThrow(new RuntimeException()).when(mockedList).clear();
mockedList.clear();
Post by Piotr Wyrwinski
**
Maybe try creating instances and define your when() with them instead of
just using any(). If I remember correctly you can use eq(), to mix
instances with any() when passing them as arguments. I realize that you
might have to change your implementation to try that, but this is where I
would start troubleshooting this.
hope this helps,
Piotr
David Karr
2013-07-30 14:55:44 UTC
Permalink
Very curious. I assume you're using "@RunWith(MockitoJUnitRunner.class)"?
I would think that if the "when" isn't matching, you should get an
exception from Mockito indicating that the "when" clause wasn't satisfied.
Have you stepped through the code in the debugger and verified that the
"restTemplate" object is actually a mock?
Post by dev danke
**
I'm having a little trouble with Mockito. I have a RestClient that wraps
Spring's RestTemplate. In a unit test of my RestClient's post() method, I
want to verify that it correctly handles a RestTemplate exception.
The problem is that my unit test doesn't trigger the mocked restTemplate
to throw an exception. I want restTemplate.exchange() to throw an
exception, but instead it just returns null.
public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}
@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}
Here's the signature of the RestTemplate method I want to throw an
public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }
Please let me know if you have any ideas on how to make this work.
Thanks,
Dan
dev danke
2013-08-02 18:43:45 UTC
Permalink
Hi David,

I wasn't using @RunWith(MockitoJUnitRunner.class) because we use TestNG.
But if TestNG has a similar runner, that could be very helpful in
diagnosing unexpected Mockito behavior. Thanks for the idea.

-Dan
Post by David Karr
**
Very curious. I assume you're using
isn't matching, you should get an exception from Mockito indicating that
the "when" clause wasn't satisfied. Have you stepped through the code in
the debugger and verified that the "restTemplate" object is actually a mock?
Post by dev danke
**
I'm having a little trouble with Mockito. I have a RestClient that wraps
Spring's RestTemplate. In a unit test of my RestClient's post() method, I
want to verify that it correctly handles a RestTemplate exception.
The problem is that my unit test doesn't trigger the mocked restTemplate
to throw an exception. I want restTemplate.exchange() to throw an
exception, but instead it just returns null.
public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}
@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}
Here's the signature of the RestTemplate method I want to throw an
public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }
Please let me know if you have any ideas on how to make this work.
Thanks,
Dan
Paulo Avelar
2013-11-09 07:00:27 UTC
Permalink
This is an old post, but I was just browsing...

I believe trading an unchecked exception for "null" is a bad idea. Alias
making methods return null is generally a bad idea. It leads to spaghetti
code. Now the caller must add if-else logic to testing for nulls... its
prone to NPE exceptions, if the caller code forget to test for nulls.
So, chances are, you are trading a specific exception,
RestClientException, for NPE exception... unless you're diligent enough to
wrap all your calls to "post" with null checks... which is a poor idea...

in this specific case, just let the caller code handle the runtime
exception.

So, if you code this according to my recommendation, your original problem
goes away...

cheers,
Paulo Avelar
Post by dev danke
I'm having a little trouble with Mockito. I have a RestClient that wraps
Spring's RestTemplate. In a unit test of my RestClient's post() method, I
want to verify that it correctly handles a RestTemplate exception.
The problem is that my unit test doesn't trigger the mocked restTemplate
to throw an exception. I want restTemplate.exchange() to throw an
exception, but instead it just returns null.
public <T> T post(String url, Object toPost, Class<T> responseType,
Object... urlVariables)
{
try
{
HttpEntity requestEntity = new HttpEntity(toPost);
ResponseEntity<T> responseEntity = restTemplate.exchange(url,
HttpMethod.POST, requestEntity, responseType, urlVariables);
return responseEntity.getBody();
}
catch (RestClientException e)
{
return null;
}
}
@Test
public void whenPostReceivesExceptionItReturnsNull()
{
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(Class.class),
any(Object[].class))).thenThrow(RestClientException.class);
Object responseBody = restClient.post("someUrl", new HashMap(),
String.class);
Assert.assertNull(responseBody);
}
Here's the signature of the RestTemplate method I want to throw an
public <T> ResponseEntity<T> exchange(String url, HttpMethod
method, HttpEntity<?> requestEntity, Class<T> responseType, Object...
uriVariables)
throws RestClientException { ... }
Please let me know if you have any ideas on how to make this work.
Thanks,
Dan
Loading...