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...
Related
I have a method signature like
public void add(byte[] key, Optional<Byte[]> secondaryKey) { ... }
My test looks something like
byte[] key = "testKey".getBytes();
byte[] secondaryKey = "secondaryKey".getBytes()
//call the method that internally calls add()
Mockito.verify(mockClass).add(key, Optional.of(ArrayUtils.toObject(secondaryKey))
The verification always fails in this case saying wanted parameters are different from actual. I have a similar add method that just take byte[] key as input parameter. Test on that method succeeds. So I think there is something wrong with the way I am trying to match Optional parameter here.
The Optional does not perform a deepEquals, therefore the equality check will fail considering that you have passed an Byte[] into the Optional.
You can see this bug report from a user that faced a similar issue. JDK-8075723
You will probably want to leverage some ArgumentMatchers to compare the arguments passed into your mock.
Since you have an Optional being passed through, you can unwrap that object using ArgumentMatchers.argThat which requires you to implement a ArgumentMatcher.matches method.
Mockito.verify(mockClass).add(ArgumentMatchers.eq(key), ArgumentMatchers.argThat(r -> {
return r.isPresent() && Objects.deepEquals(secondaryKey, r.get())
));
Edit:
You can also use ArgumentCaptor if you prefer to capture the state of the parameters passed into the mocks and perform assertions.
ArgumentCaptor<Optional> captor =ArgumentCaptor.forClass(Optional.class)
verify(pojo).add(eq(key), captor.capture());
Optional<byte[]> result = captor.getValue();
assertTrue(result.isPresent());
assertArrayEquals(secondaryKey, result.get());
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.
Is there any junit assertion, with which i can force a line to be executed?
For example:
doAnswer(new Answer<Void>() {
#SuppressWarnings("unchecked")
#Override
public Void answer(final InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
Map<String, String> fieldMapActual = (Map<String, String>) arguments[0];
assertEquals(fieldMap, fieldMapActual);
**assertFailIfThisLineIsNotExecuted();**
return null;
}
}).when(x).myMethod(xxx);
As i simulate the behaviour of myMethod, the method answer from the anonymous inner type will be executed at runtime of the myMethod (not at runtime of junit test), if myMethod will be called with the intended value/parameter.
In order to assert that the method is called, i must additionally define a verify (otherwise my test would still run even if the method is not called).
verify(x).myMethod(xxx);
If i had a chance to write sth like assertFailIfThisLineIsNotExecuted in the answer method, i would not have to define an extra verify. So again, Is there any junit assertion, with which i can force a line to be executed? Opposite of fail() so to speak, without immediately defining the method as "successful".
If you want to make sure that a certain line of your test is being executed, use a boolean flag:
final boolean[] wasExecuted = { false };
...
wasExecuted[0] = true;
...
assertTrue("Some code wasn't executed", wasExecuted);
But my gut feeling is that you're trying to solve a different problem.
The verify says "This method must have been called". It doesn't matter if you mocked an answer or not. So this is the approach that you should use.
I'm using my flag approach only when I can't create a mock for some reason. If that happens, I extend the class under test in my test code and add the flag.
The advantage of the flag over verify is that the flag documents in which place I expect the code to be (you can have the IDE search all places where the flag is used). verify() is not that easy to locate when it fails.
verify(x).myMethod(xxx); should be what you want. It also expresses intent.
assertFailIfThisLineIsNotExecuted() would also be a single line of code (so how would it be "better" than verify?), it's not supported by JUnit, you would have to write code to get a good error message, etc.
I have a Java component that receives a payload (JsonData), like this:
public String myMethod(JsonData payload) throws IOException {
// do things with payload.
}
This is working fine, but I also need to access a flow variable within the method. I understand that, to do so, I need to run myMessage.getInvocationProperty("my-variable-name");
However, since I'm only passing the payload, I don't have access to the MuleMessage. How can I change my method so I can get access to my message/property?
I tried:
org.mule.RequestContext.getEvent().getMessage()
but it is deprecated.
Also, I've read all sorts of answers on this issue but never found a complete answer.
Thanks,
Pass the flow variable as a second argument to myMethod via the invoke message processor.
So, assuming the new signature of myMethod is:
public String myMethod(JsonData payload, String myVariable) throws IOException {
// do things with payload.
}
you would do:
<invoke object-ref="myComponent"
method="myMethod"
methodArguments="#[message.payload],#[flowVars['my-variable-name']]" />
Use the message.getInvocationProperty method.
Setting variable:
<set-variable variableName="lastname" value="#[payload.lastname]" />
Retrieve variable from invocation scope:
String lastname = message.getInvocationProperty("lastname");
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"));