4

I have the following method for which I'm trying to write unit test using Mockito. I'm fairly new to Mockito and trying to catch up.

Method to test

public synchronized String executeReadRequest(String url) throws Exception{

    String result = null;
    RestClient client = null;
    Resource res = null;
    logger.debug("Start executing GET request on "+url);

    try{
         client = getClient();
         res = client.resource(url);
         result = res.contentType(this.requestType).accept(this.responseType).get(String.class);
    }
    catch(Exception ioe){
        throw new Exception(ioe.getMessage());
    }
    finally{
        res = null;
        client = null;
    }

    logger.info("GET request execution is over with result : "+result);
    return result;
}

The unit test with Mockito

@Test
public void testRestHandler() throws Exception {
    RestHandler handler = spy(new RestHandler());
    RestClient mockClient = Mockito.mock(RestClient.class,Mockito.RETURNS_DEEP_STUBS); 
    Resource mockResource = Mockito.mock(Resource.class,Mockito.RETURNS_DEEP_STUBS);

    doReturn(mockClient).when(handler).getClient();
    Mockito.when(mockClient.resource(Mockito.anyString())).thenReturn(mockResource);

  //ClassCastException at the below line
    Mockito.when(mockResource.contentType(Mockito.anyString()).accept(Mockito.anyString()).get(Mockito.eq(String.class))).thenReturn("dummy read result");

    handler.setRequestType(MediaType.APPLICATION_FORM_URLENCODED);
    handler.setResponseType(MediaType.APPLICATION_JSON);
    handler.executeReadRequest("abc");
}

But I'm getting a ClassCastException at the line

Mockito.when(mockResource.contentType(Mockito.anyString()).accept(Mockito.anyString()).get(Mockito.eq(String.class))).thenReturn("dummy read result");

Exception

java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$4b441c4d cannot be cast to java.lang.String

Appreciate any help to resolve this.

Many thanks.

Benjamin Hodgson
  • 42,952
  • 15
  • 108
  • 157
user1356042
  • 395
  • 2
  • 6
  • 23

2 Answers2

3

This style of chaining during stubbing isn't correct:

Mockito.when(
    mockResource.contentType(Mockito.anyString())
        .accept(Mockito.anyString())
        .get(Mockito.eq(String.class)))
    .thenReturn("dummy read result");

Even though you've set the mocks to return deep stubs, Matchers work via side-effects, so this line doesn't achieve what you think it does. All three matchers (anyString, anyString, eq) are evaluated during the call to when, and the way you have it your code is likely to throw InvalidUseOfMatchersException at the slightest provocation—including adding unrelated code or verifications later.

This means your problem isn't the use of eq(String.class): It's that Mockito is trying to work the Class matcher in where it doesn't belong.

Instead, you'll need to stub specifically:

Mockito.when(mockResource.contentType(Mockito.anyString()))
    .thenReturn(mockResource);
Mockito.when(mockResource.accept(Mockito.anyString()))
    .thenReturn(mockResource);
Mockito.when(mockResource.get(Mockito.eq(String.class))) // or any(Class.class)
    .thenReturn("dummy read response");

Note that some of the difficulty here is that Apache Wink uses the Builder pattern, which can be laborious in Mockito. (I've returned mockResource here, but you could imagine returning specific other Resource objects, at the expense of requiring them in exactly that order later.) A better way might be to use a default Answer that returns this whenever possible.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
-2

Solved it by changing the get call to

get(Mockito.any(Class.class))
user1356042
  • 395
  • 2
  • 6
  • 23
  • While this code may answer the question, it would be better to include some context, explaining how it works and when to use it. Code-only answers are not useful in the long run. – Bono Jan 30 '16 at 10:29