Java – Problems when trying to emulate the Apache HTTP client with Mockito

Problems when trying to emulate the Apache HTTP client with Mockito… here is a solution to the problem.

Problems when trying to emulate the Apache HTTP client with Mockito

I’m a beginner at Mockito. I have an HTTP get call and I want to mock it.

The Utility file to test is this.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

public class GoogleAccessor {
private HttpClient client ;

public void getGoogle() throws ClientProtocolException, IOException {
        String url = "http://www.google.com/search?q=httpClient";
         client = new DefaultHttpClient();
        HttpGet request = new HttpGet(url);
        try {
            HttpResponse response = client.execute(request);
            BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer result = new StringBuffer();
            String line = "";
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
            System.out.println(result);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

}

Here is my jUnit test

import static org.mockito.Mockito.when;

import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import org.mockito.Mock;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

public class TestTest {

@Mock
    private HttpClient mClient;

@InjectMocks
    private GoogleAccessor dummy;

@Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

@Test
    public void testAddCustomer_returnsNewCustomer() throws Exception {
        when(mClient.execute(Mockito.any())).thenReturn(buildResponse(201, "OK", "{\"message\":\"Model was stored\"}"));
        dummy.getGoogle();
    }

BasicHttpResponse buildResponse(int statusCode, String reason, String body) {
        BasicHttpResponse response = new BasicHttpResponse(
                new BasicStatusLine(new ProtocolVersion("HTTP", 1, 0), statusCode, reason));
        if (body != null) {
            response.setEntity(new ByteArrayEntity(body.getBytes()));
        }

return response;
    }
}

I keep getting this error because mclient is not starting

java.lang.NullPointerException
    at com.amazon.cartographertests.accessors.TestTest.testAddCustomer_returnsNewCustomer(TestTest.java:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    ...

Update 1: I merged @glytching’s comment and removed variable initialization in setup().
I merged @Maciej Kowalski’s comments and made the client a class variable in the Utility class

Update 2:

After parsing to the correct import -> import org.mockito.mock, the NPE error has been resolved;

However, the problem of not seeing the mock response persists

Solution

You declare mClient as impersonation here:

@Mock
private HttpClient mClient;

But you also assign a concrete instance of DefaultHttpClient to it in setUp().

mClient = new DefaultHttpClient();

Simply remove the line from setup() and the mClient instance used in your test will be a mock.

Update: The issue that you updated shows this import:

import org.easymock.Mock;

It should be

import org.mockito.Mock;

This directive: MockitoAnnotations.initMocks(this); Will initialize any class member annotated with org.mockito.mock, it won’t do anything to the class member annotated with org.easymock.mock so I suspect mClient is not initialized, hence NPE. When I run your code locally and import it correctly, the test completes successfully without exceptions.

Note: There is also an issue in GoogleAccessor, where you explicitly instantiate HttpClient in getGoogle….

HttpClient client = new DefaultHttpClient();

… So this method will never use the mock HttpClient.

If you comment out this line:

HttpClient client = new DefaultHttpClient();

… and add such members to GoogleAccessor:

private HttpClient client;

… Then you will find that your mock client will be used in getGoogle().

Background; In order to use mock instances in a class, you must provide methods for the test runner to inject mock instances into the class. In your test case, you are using @InjectMocks, so you instruct the test runner to inject your mock into GoogleAccessor but because there is no class member of that type, the test runner has nothing to assign mocks to. Also, even though it can assign the mock to something, you declare the http client in inside getGoogle(), forcing all calls to the method to use a concrete instance of DefaultHttpClient.

Related Problems and Solutions