Using Mockito for HTTP Client - java

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

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.

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.

First understand meaning of Mocking.
1)Why we need mocking?
Suppose we don't want to call any original method and want that instead of that original method we should call a dummy method then we should go for mocking.
For e.g:
Mockito.when(mockHttpClient.execute(mockHttpPost)).thenReturn(mockHttpResponse)
This means whenever this execute() will be called then you will return your own prepared value instead of original mockHttpResponse.
So in your case prepare your stub object and mockit if you need that.
Here you prepare your response(Note actual but dummy).
mockHttpResponse.setEntity(new Entity());
mockHttpResponse.getEntity().setContent('{yourJsonString}');
So whenever your
mockHttpClient.execute(mockHttpPost); //will be called
Then it will return the response that you prepared in your test method manually.
When your control comes to
new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
Then you will get {yourJsonString} when response.getEntity().getContent() is called and let rest code do its functionality. At end your JSON stubbed object will be prepared.
Remember test cases are just for developers help.We can mock anything and return anything or any stub object.Just we write test case to check our control flow by passing expected and non expected values.
This will make your work easy.Now you want to mock your BufferReader class use this.
BufferedReader bufferedReader = org.mockito.Mockito.mock(BufferedReader.class);
when(bufferedReader.readLine()).thenReturn("first line").thenReturn("second line");
org.junit.Assert.when(new Client(bufferedReader).parseLine()).thenEquals(IsEqual.equalTo("1"));

Related

How to test a simple given method using Mockito

I am new to testing with java so it confuses me a little how to write a proper unit test to a method with no parameters and return value. In general the snippet looks like the below:
public class SplitterService {
private SentenceDAO sentenceObject;
private ObjectToXML objectToXML;
private ObjectToCSV objectToCSV;
public SplitterService(int selector, String inputPath, String outputPath) {
this(inputPath);
if (selector == 1)
objectToCSV = new ObjectToCSV(outputPath, size);
if (selector == 2)
objectToXML = new ObjectToXML(outputPath);
}
public void chooseConverter() {
if (objectToCSV != null)
objectToCSV.printRecord(sentenceObject);
if (objectToXML != null)
objectToXML.marshal(sentenceObject);
}
}
There are 3 private fields in the class. There is also a constructor which instantiate a given class. Then in the chooseConverter() method a proper action is taken according to the created object.
Could you please give me some advice how to test the chooseConverter method since there is no return value and a parameter (I know Junit 5 and a little of Mockito). Im not looking for any given solution just a few words how to approach my issue.
The code, in its current form, is not unit-test friendly.
As a last resort, you can test the side effects of ObjectToCSV and ObjectToXML, but lets try to do better than that.
Ideally, the class should provide some injection points to allow you inject new mock instances of ObjectToCSV and ObjectToXML.
There are multiple ways to introduce DI like providing factories for these objects in a constructor, extracting a factory of SplitterService which injects objectToCSV or objectToXML depending on the selector.
These methods require some modifications of the client code.
extracting methods that create instances of objectToCSV and objectToXML from the constructor requires a minimal code change and is transparent to the clients. In such case, you subclass your class and override builder methods to return mocks.
if no modifications to existing code are allowed, I can recommend pulling in Powermock and mocking the constructors. Note: you must be running junit4 vintage engine, as Powermock hasnt been ported to jUnit5 yet.
https://dzone.com/articles/using-powermock-mock
you are looking at a few things here... first check that objectToCSV::printRecord (objectToCSV will be a Mockito mock) is getting called under the condition objectToCSV != null (and objectToXML:: marshal is getting called under objectToXML != null). And also you are looking for ArgumentCaptor most probably, that is to test that objectToCSV::printRecord and objectToXML.marshal is actually getting called with sentenceObject that you set.

Mock a Method with complex type

While mocking a method, which have complex type, returning null in java
public void sendRequest(OnlineRequest request) {
OnlineResponse response = client.handleRequest(request);
System.out.println( response);
}
Mockito.when(client.handleRequest(request)).thenReturn(new OnlineResponse());
If I understand correctly, your issue is that System.out.println(response); prints null?
This is most likely due to the fact that client.handleRequest() is not being called with the request you expect. This may be an error somewhere in code you haven't provided us, OR it may simply be due to the fact that OnlineRequest does not have an implementation of equals/hash-code, so when() is never triggered because it is not called with the exact same instance of OnlineRequest as you use in your unit tests.
You might wish to test that handleRequest is called with exactly the object you expect. This can be accomplished using verify():
verify(client).handleRequest(request);
in your unit test. This too is dependent on the equals/hash-code implementation to determine whether request is the expected parameter or not.

Mockito capture argument on "recording" time and use it later on execution time

I have the following code which I want to test:
pojo.setStatus(Status.INITIAL);
pojo.setExecutionCounter(0);
//eventRepository is a mock
scheduleEvent(this.eventRepository.save(pojo).get());
In a unit test, I'd like to verify that
the pojo has been modified accordingly
The event which will be scheduled has status INITIAL and the counter is 0
save of the mock has been called
Unfortunately, I have no clue how to do that, since I have to return the argument which I have to capture. Maybe it's getting more clear when I show the example of my unit test:
succeededEvent.setEventStatus(INITIAL);
succeededEvent.setExecutionCounter(0);
//Actually we want here to return the argument
//which is captured by eventArgumentCaptor??
when(this.eventRepository.save(this.eventArgumentCaptor.capture()))
.thenReturn(succededEvent);
this.processor.processEvent(initialEvent);
Mockito.verify(this.eventRepository,
Mockito.times(1)).save(eventCaptureExecuteCaptor.capture());
final Event capturedEvent = eventCaptureExecuteCaptor.getValue();
//Counter and status should be reset
assertEquals(new Integer(0), capturedEvent.getExecutionCounter());
assertEquals(INITIAL, capturedEvent.getEventStatus());
verify(this.eventRepository,
times(1)).save(eq(eventCaptureExecuteCaptor.getValue()));
Not sure why you need to use captor while stubbing.
You use it, as designed, after the invocation of the SUT:
this.processor.processEvent(initialEvent);
Mockito.verify(this.eventRepository,
Mockito.times(1)).save(eventCaptureExecuteCaptor.capture());
While stubbing, you can directly go for the concrete object that is expected:
when(this.eventRepository.save(succededEvent)
.thenReturn(succededEvent);
or use a generic input if you do not have that object at hand on set-up:
when(this.eventRepository.save(anyClass(EventPojo.class))
.thenReturn(succededEvent);
Edit:
You can also use the thenAnswer along with accepting any input class of Pojo type:
when(this.eventRepository.save(Mockito.any(EventPojo.class))
.thenAnswer(new Answer<EventPojo>(){
EventPojo pojo = invocation.getArgument(0);
return pojo;
}
);
as this is an anonymous implementation, you can catch the state of the passed pojo if you have the need.

Mock method with Consumer

I want to mock repository.actionOnFile(String path, Consumer<InputStream> action) in this source:
#Autowired
private FileRepositoryService repository;
public Document getDocument(URL url) {
MutableObject<Document> obj = new MutableObject<>();
Consumer<InputStream> actionOnFile = inputStream -> obj.setValue(getDocument(inputStream));
try {
repository.actionOnFile(url.toExternalForm(), actionOnFile);
} catch (S3FileRepositoryException e) {
throw e.getCause();
}
return obj.getValue();
}
The problem is that the second argument is a lambda expression.
How to mock it with mockito, I need to pass to the accept method the input stream to test it?
I found solution!
doAnswer(ans -> {
Consumer<InputStream> callback = ans.getArgument(1, Consumer.class);
InputStream stream = new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8));
callback.accept(stream);
return null;
}).when(repository).actionOnFile(eq("any"), any(Consumer.class));
If you only want to mock the Function argument then the following would work:
Mockito.when(convertStringtoInt(Mockito.any(String.class), Mockito.any(Consumer.class))).then[...]
How to mock it with mockito, I need to pass in accept method test
input stream?
In your case, you want to test the getDocument() method.
So what you need to mock is the dependency of the class under test :
that is the repository field.
actionOnFile.add() more specifically should be mocked.
According to your code, either the method should throw S3FileRepositoryException or it provokes a side effect not visible in the code.
In the exception scenario, you should write something as :
 Mockito.when(fileRepositoryServiceMock.actionOnFile(url.toExternalForm(), actionOnFile)).thenThrow(new S3FileRepositoryException(cause));
And in the successfull, you should just verify that the method is invoked :
 Mockito.verify(fileRepositoryServiceMock).actionOnFile(url.toExternalForm(), actionOnFile));
Mocking a Consumer is really not a big deal.
It is a interface, you can mock any interface with Mockito.
The real issue is actually the Consumer makes not part of the API of the tested method.
It is a local variable.
Besides, it relies on an inputStream field that is not show in the code.
You cannot and have not to mock internal things.
Note that it also relies on a overloaded getDocument() method that is not mocked. So you would need to provide a consistent InputStream if you want to getDocument() that accepts a inputStream doesn't throw an exception.
Long story short : I think that you should either rethink your design to extract the depending processings in another class or write an integration test.

Verify Overloaded Method Call

I am attempting to verify that a method was called a number of times using the Mockito verify functionality. The problem I am encountering however is that the method is overloaded so it claims that the method was not called. To Add a wrench into the mix, I also wish to capture what the argument was that was passed to this method. Here is what I have so far:
#Test
public void simpleTest() throws IOException {
FlumeAppender mockAppender = Mockito.mock(FlumeAppender.class);
ArgumentCaptor<LoggingEvent> arguments = ArgumentCaptor.forClass(LoggingEvent.class);
// Load the message that should be sent to the class being tested
InputStream in = this.getClass().getResourceAsStream("/testMessage.xml");
StringWriter writer = new StringWriter();
IOUtils.copy(in, writer, "UTF-8");
String testMessage = writer.toString();
// Send a message to the class being tested. This class will
// (hopefully) call the function I am listening to below
eventSubscriber.handleMessage(testMessage);
// Verify that the append method was called twice
Mockito.verify(mockAppender, Mockito.times(2)).append(
arguments.capture());
// Do something with the arguments
}
Like I said, the function I am attempting to verify (append) is overloaded. Is it possible to specify which append function I am asking to verify while still capturing the arguments?
Embarrassingly, I have discovered the solution to my problem was the result of a simple error. I will post the answer for reference.
When creating the ArgumentCaptor, specify the argument type you are expecting using generics. I had done this, but sadly I used the type from one of the other versions of the method that I was not expecting to be called. Simple mistake.
// This declaration
ArgumentCaptor<LoggingEvent> arguments = ArgumentCaptor.forClass(LoggingEvent.class);
// Should have been:
ArgumentCaptor<Event> arguments = ArgumentCaptor.forClass(Event.class);
Once this is correct the verify function should work as expected, using the type from the ArgumentCaptor to determine which method to look at.
So close...

Categories

Resources