3

I searched on the forum and tried to get some heads up, by experimenting what others have already mentioned in other related posts but nothing worked for me since I am new to mockito junit, hence posting this question.

I have a rest client , which calls Rest webservice :-

// Rest Client code
public static String getProcessString(String url) {
Client client = Client.create();
com.sun.jersey.api.client.WebResource webResource = client.resource(url);
webResource.accept("application/json");
/*if (response.getStatus() != 200) {
       throw new RuntimeException("Failed : HTTP error code : "
        + response.getStatus());
    }*/
String process = webResource.get(String.class);

return process;

}

My plan is to unit test getProcessString(String url) method. My RestClientUnitTest.java code is shown below:-

package......service.workflow.client;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
@RunWith(MockitoJUnitRunner.class)
public class RestClientUnitTest {
    @InjectMocks
    private  RestClient  RestClient = new  RestClient();

    @Mock
    private com.sun.jersey.api.client.WebResource res;





    @Mock
    private Client client;

    private String URL = "http://localhost:9095/jersey/recoveryservice/fetchUpdateProcesses?oldProcessDefinitionId=maker_checker&newProcessDefinitionId=maker_checker_v1";
    @Before
    public void setUp() throws Exception {
        Client mockClient = Client.create();
        doReturn(mockClient).when(client).create();
        //WebResource webResource = mockClient.resource(URL);
        doReturn(webResource).when(mockClient).resource(URL);
        //when(mockClient.resource(URL)).thenReturn(res);
        doReturn("OK").when(res).get((Class<String>) any());
        //when(webResource.get((Class<String>) any())).thenReturn("OK");

    }

    @Test
    public void testgetProcessString() {
        Assert.assertEquals(RestClient.getProcessString("http://localhost:9095/jersey/recoveryservice/fetchUpdateProcesses?oldProcessDefinitionId=maker_checker&newProcessDefinitionId=maker_checker_v1"), "OK");
        /*Client client = Client.create();
        com.sun.jersey.api.client.WebResource webResource = client.resource(url);
        webResource.accept("application/json");
        if (response.getStatus() != 200) {
               throw new RuntimeException("Failed : HTTP error code : "
                + response.getStatus());
            }
        String process = webResource.get(String.class);

        return process;*/
    }

}

However my unit test is failing at :- doReturn(webResource).when(mockClient).resource(URL); error trace is :-

 org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at .......service.workflow.client.RestClientUnitTest.setUp(RestClientUnitTest.java:35)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. although stubbed methods may return mocks, you cannot inline mock creation (mock()) call inside a thenReturn method (see issue 53)

    at ......service.workflow.client.RestClientUnitTest.setUp(RestClientUnitTest.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Not sure what am I missing here? Any ideas and suggestions will be appreciated

After some analysis, tweaked the code in setUp() method as :-

    Client mockClient =Client.create();
    //WebResource mockWebResource = Mockito.mock(WebResource.class);
    //when(client.create()).thenReturn(mockClient);
    doReturn(mockClient).when(client).create();
     res = mockClient.resource(URL);

    when(res.get((Class<String>) any())).thenReturn("OK"); ---> Error
    //stub(res.get((Class<String>) any())).toReturn("OK");

So no more getting the earlier exception, but now it seems trying to actually connect at the URL for webResource.get() and hence giving below error:-

  com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
    at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:148)
    at com.sun.jersey.api.client.Client.handle(Client.java:642)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:601)
    at com.sun.jersey.api.client.WebResource.get(WebResource.java:187)
    at ........service.workflow.client.RestClientUnitTest.setUp(RestClientUnitTest.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
kunal
  • 93
  • 1
  • 2
  • 7

1 Answers1

1

To your 1st error log: it tells you how you should use the API:

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);

To your second error: you call Client mockClient = Client.create(); which is NOT mocking, but calling a real method.

This is how you should do it:

//First you create a mock with an annotation
@Mock
private Client clientMock;

// ...

// Then you define special behaviour, e.g.
when(clientMock.foo()).thenReturn("bar");

// Then you use the mock instance:
assertEquals("bar", clientMock.foo());

However, you are mocking Jersey's Client but you do not set that mocked instance to your RestClient, and therefore it is using the real one. Either you introduce a setter to RestClient which sets the Client instance (which is not very nice), or you get more sophisticated and mock Client.create(), which is a static method and Mockito is not able to mock static methods. Instead you can take a look at PowerMock (which uses Mockito; it still has some limitations) or JMockit (which is a complete and mighty mocking-framework, but documentation is quite short)

Andy
  • 1,964
  • 1
  • 15
  • 29
  • Thanks for your reply @Andy .. really appreciated.. Yes I agree with you that to inject the Client instance in Rest Client may involve refactoring and changing large portions of code which would be directly calling RestClient.java. So as you have suggested I am trying to use JMockit 0.991 as that only is available in our organization's firmwide maven repo. Anyways will keep you updated of my progress. Thanks again – kunal Jan 19 '14 at 09:39