Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Mockito for HTTP Client

I have a stubbed JSON OBJECT but need to mock the following using Mockito:

HttpResponse response = defaultHttpClient.execute(postRequest);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder result = new StringBuilder();
while ((line = rd.readLine()) != null) {
    result.append(line);        
}
JSONObject jsonResponseObject = new JSONObject(result.toString()); 

I have created the following Mocks:

@Mock
    private HttpClient mockHttpClient;
    private HttpPost mockHttpPost;
    private HttpResponse mockHttpResponse;
    private HttpEntity mockHttpEntity; 
    private InputStream mockInputStream;
    private InputStreamReader mockInputStreamReader;
    private BufferedReader mockBufferedReader;

And have the following when statements:

    Mockito.when(mockHttpClient.execute(mockHttpPost)).thenReturn(mockHttpResponse); 
    Mockito.when(mockHttpResponse.getEntity()).thenReturn(mockHttpEntity);
    Mockito.when(mockHttpEntity.getContent()).thenReturn(mockInputStream);

Question: Do I need to create all these 'when' statements and if yes then which other ones do I need to create to be able to get to the stubbed JSON?

Any suggestions pls?

Thanks

like image 550
Global Dictator Avatar asked Dec 13 '13 10:12

Global Dictator


People also ask

Can we mock HttpClient java?

In mockito you can mock all: interfaces, abstract classes, normal classes. In your case, if you want to simulate the behaviour of only execute() method you can mock the HttpClient interface.

Can we mock interface using Mockito?

The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called.

What can be mocked with Mockito?

Mockito mock method We can use Mockito class mock() method to create a mock object of a given class or interface. This is the simplest way to mock an object. We are using JUnit 5 to write test cases in conjunction with Mockito to mock objects.

How do you mock a WebClient call?

We have two main options for mocking in our tests: Use Mockito to mimic the behavior of WebClient. Use WebClient for real, but mock the service it calls by using MockWebServer (okhttp)


2 Answers

You might have to mock HttpClient and HttpResponse, if they're interfaces (although, depending on your library, you could use MockHttpClient or MockHttpResponse), but you shouldn't be mocking anything else.

Why?

The mock is establishing expected output behavior on classes that we cannot make concrete, or rather, classes that we want to behave in a certain way for this particular instance of a test. You want to ensure that you get the correct response back from a mock HttpClient, and that when response.getEntity() is called, that it gives back a meaningful HttpEntity. You can elect to mock that out or not; I personally wouldn't, as the mock doesn't add any extra value (except to perhaps verify that a particular method was called).

Everything else is a concrete implementation - you should be allowing the other objects to interact with the results of the previously mocked elements to ensure that they behave as they would if there were no mocks.

Actually...you really can't mock those unless you pass them in or inject them in some way. I would strongly discourage you from attempting to mock any newed objects in that method.

You don't specify what you're asserting, but I would expect that it's your JSONObject in some capacity. I'd assert that what you expected to be placed into it actually made it into the JSON object, and also verify that your mocked objects were called and invoked in the way you expected them to be.

Your annotation @Mock is not cascading, by the way - you have to annotate all mocked fields with @Mock, then either annotate the test class with @RunWith(MockitoJunitRunner.class), or use MockitoAnnotation.initMocks(this) (one or the other; both aren't required except under edge cases). If you choose the annotations, don't forget @InjectMocks on your test object.

Lastly, your when conditions do what I would expect them to do - those should be fine.

like image 146
Makoto Avatar answered Sep 21 '22 18:09

Makoto


Yes, you might need all the when statements that you've mentioned. But instead of returning the mockInputStream, you could just return new ByteArrayInputStream( "{foo : 'bar'}".getBytes() )

Finally, you could verify that the json response object has a 'foo' property that has a value 'bar'.

That said, I'm not sure whether the given method is worth testing - since all it does it open streams and read data.

like image 21
aquaraga Avatar answered Sep 17 '22 18:09

aquaraga