How to verify multiple method calls with different params - java

I have the following method that I wish to verify behaviour on.
public void methodToTest(Exception e, ActionErrors errors) {
...
errors.add("exception.message",
ActionMessageFactory.createErrorMessage(e.toString()));
errors.add("exception.detail",
ActionMessageFactory.createErrorMessage(e.getStackTrace()[0].toString()));
...
}
In my #Test class I was hoping to do something like this to verify that errors.add() is called with "exception.message" and again with "exception.detail"
verify(errors).add(eq("exception.message"), any(ActionError.class));
verify(errors).add(eq("exception.detail"), any(ActionError.class));
however Mockito complains as follows
Argument(s) are different! Wanted:
actionErrors.add(
"exception.message",
<any>
);
Actual invocation has different arguments:
actionErrors.add(
"exception.detail",
org.apache.struts.action.ActionError#38063806
);
How can I tell Mockito to check for both values?

Further reading has led me to try using ArgumentCaptors and the following works, although much more verbose than I would like.
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(errors, atLeastOnce()).add(argument.capture(), any(ActionMessage.class));
List<String> values = argument.getAllValues();
assertTrue(values.contains("exception.message"));
assertTrue(values.contains("exception.detail"));

If the order of both add() calls is relevant, you can use InOrder:
InOrder inOrder = inOrder(errors);
inOrder.verify(errors).add(eq("exception.message"), any(ActionError.class));
inOrder.verify(errors).add(eq("exception.detail"), any(ActionError.class));

Try something like this:
verify(errors, times(2))
.add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
any(ActionError.class));

You can use Mockito.atLeastOnce() which allows Mockito to pass the test even if that mockObject will be called many times.
Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));
Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));

you probably have a problem in your code. Because as a matter of fact you actually write this code:
Map<Character, String> map = mock(Map.class);
map.put('a', "a");
map.put('b', "b");
map.put('c', "c");
verify(map).put(eq('c'), anyString());
verify(map).put(eq('a'), anyString());
verify(map).put(eq('b'), anyString());
Note the first verify is not even in order in regard of the actual invocations.
Also, I would recommand you to actually don't mock types you don't own, eg the struts type.
[EDIT #Brad]
After running Brice's code (above) in my IDE I can see that I have used ActionError instead of ActionMessage, so that is why my verify() was not matching. The error message I initially posted was misleading me into thinking it was the first argument that was not matching. It turns out it was the second argument.
So the answer to my question is
/**
* note that ActionMessageFactory.createErrorMessage() returns ActionMessage
* and ActionError extends ActionMessage
*/
verify(errors).add(eq("exception.message"), any(ActionMessage.class));
verify(errors).add(eq("exception.detail"), any(ActionMessage.class));

OP code is correct (check your Total)
=1= Tell Mokito the total call expectation.
=2= Tell Mokito how many times each parameter combination was expected. (Mokito assumes times(1), if times is omitted).
verify(errors, times(2)).add(any(), any(ActionMessage.class));
verify(errors).add(eq("exception.message"), any());
verify(errors).add(eq("exception.detail"), any());
The OP code is correct; it checks what you need.
Your problem was in your Prod code, which (seems) never called the first arg combination with ActionError arg type. So Mokito correctly complained. However (I agree) the complaint message is confusing for the multiple calls.
SOLUTION: Ensure (first of all) you really called the method precisely 2 times (with any args).

In a similar way to #sendon1928 we can use:
Mockito.times(wantedInvocationCount)
to make sure method was called exact number of times (preferable solution in my opinion). Afterwards, we can call
Mockito.verifyNoMoreInteractions(mock)
To make sure that mock was not used further in any context. Full example:
Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(1));
Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(2));
Mockito.verifyNoMoreInteractions(mockObject)

Related

JUnit assertion to force a line to be executed

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.

JMockit - "Missing invocation to mocked type" when mocking System.getProperties()

I am admittedly new to JMockit, but I am for some reason having trouble mocking System.getProperties(). Thanks to the help of following post:
https://stackoverflow.com/questions/25664270/how-can-i-partially-mock-the-system-class-with-jmockit-1-8?lq=1
I can successfully mock System.getProperty() using JMockit 1.12:
#Test
public void testAddSystemProperty_String() {
final String propertyName = "foo";
final String propertyValue = "bar";
new Expectations(System.class) {{
System.getProperty(propertyName);
returns(propertyValue);
}};
assertEquals(propertyValue, System.getProperty(propertyName));
}
But the eerily similar code for mocking getProperties() barfs:
#Test
public void testAddSystemProperty_String() {
final String propertyName = "foo";
final String propertyValue = "bar";
final Properties properties = new Properties();
properties.setProperty(propertyName, propertyValue);
new Expectations(System.class) {{
System.getProperties();
returns(properties);
}};
assertEquals(1, System.getProperties().size());
}
I get the following exception that points to the "returns" method:
Missing invocation to mocked type at this point;
please make sure such invocations appear only after
the declaration of a suitable mock field or parameter
Also, how do I mock both methods at the same time? If I put them in the same Expectations block (with the getProperty() first), then I do not see the exception, but System.getProperties() returns the real system properties, not the mocked ones; though getProperty(propertyName) returns the mocked value. I find that totally wonky behavior.
I see from this post that certain methods cannot be mocked, but System.getProperties() is not on that list:
JMockit NullPointerException on Exceptions block?
I am also finding that a lot of solutions on SO that worked with JMockit 2-3 years ago are totally non-compilable now, so apparently things change a lot.
System.getProperties() is indeed one of the methods excluded from mocking in JMockit 1.12. The exact set of such excluded methods can change in newer versions, as new problematic JRE methods are found.
There is no need to mock System.getProperty(...) or System.getProperties(), though. The System class provides setProperty and setProperties methods which can be used instead.
Hopefully someone else finds this useful:
This can be solved with Mockito / PowerMock (1.5.3).
Note that I am testing a utility that will exhaustively try to find the property value given a list of possible sources. A source could be a system property, an environment variable, a meta-inf services file, a jndi name, a thread local, a file on disk, an ldap, basically anything that can perform a lookup.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassThatDirectlyCallsSystemInCaseItIsNestedLikeInMyCase.class})
public class ConfigPropertyBuilderTest {
#Test
public void testAddSystemProperty_String_using_PowerMockito() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty(propertyName)).thenReturn(propertyValue);
PowerMockito.when(System.getProperties()).thenReturn(new Properties() {{
setProperty(propertyName, propertyValue);
}});
// Here is realistic case of calling something that eventually calls System
// new configBuilder().addEnvironmentVariable(propertyName)
// .addSystemProperty(propertyName)
// .getValue();
// Here is simplified case:
assertEquals(1, System.getProperties().size());
assertEquals(propertyValue, System.getProperty(propertyName));
}
}
I could call System.setProperty(), but when you start getting into the other sources, it becomes less clear.
Note that I do not specifically care about the value returned by System.getProperty() either; I simply want to ensure that it is called if the first look up fails.
For example, in the above code snippet, the environment variable does not exist, so System.getProperty() should be called. If the environment variable existed (as it does in the next test case which is not shown), then I want to verify that System.getProperty() was not called because it should have short circuited.
Because of the difficulties in faking out the other sources using real files, real ldap, real APIs, etc, and because I want to verify certain APIs are either called or not called, and because I want to keep the tests looking consistent, I think mocking is the correct methodology (even though I may be trying to mock stuff that is not recommended in order to keep it all looking consistent). Please let me know if you think otherwise.
Also, while I do not understand the difficulties of maintaining these mocking frameworks (especially the cglib based ones), I understand the difficulties do exist and I can appreciate the sort of problems you face. My hat goes off to you all.

how to use mockito spy for lazy evaluation?

I want to use mockito spy.
When I set a return value in both following ways:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate));
doReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate)).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
I see the return value is being evaluated eagerly
meaning when this "setting" line is executed.
how can i force the spy to evaluate the return value only on demand?
meaning when the "when" condition is met.
update
Thanks to #RobbyCornelissen I have tried this code:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
ImagesSorter mock = (ImagesSorter)invocation.getMock();
return mock.sortImages((List<Image>)args[0], (UserInfo)args[1], fakeNowDate);
}
});
But it didn't help:
1) the "when" expression was invoked immediately. (not wanted)
2) eventually the callback wasn't call.
First let me warn you on partial mocks, because that is what the code is actually doing, it's wrong design wise. It may be more relevant to use a strategy pattern to compose behavior of the tested subject. Mockito team (including me) strongly advises to stay away of partial mocks whenever possible.
EDIT : I don't know the code and I don't know exactly which component under test but from what I gather there's a type responsible to sort images, let's call it ImagesSorter.
So first case ImagesSorter is a dependency of a test subject, so in this case just stubbing the mock of ImagesSorter will do.
If however it is ImagesSorter itself under test, and stubbing a special method of this class is called a partial mock and it is plain wrong. It exposes internal of the production code in the test. So there's several solutions.
As the code snippet showed in the answer shows a fakeDate, one of the solution is to not use things like new Date() and code a simple class TimeSource whose sole responsibility is to provide a date. And in tests the bwhavior of this TimeSOurce could be overriden.
A simplier solution would be to use JodaTime as it provides this functionality built in.
If the scope of test goes beyond changing the date, then maybe ImagesSorter needs a way to be configured with other objects. Inspiration on how to do it can be found with the cache builder of guava. If the configuration is dead simple then a simple constructor coud do it.
That could look like :
class ImagesSorter {
ImagesSorterAlso algo;
ImagesSorter(ImagesSorterAlgo algo) { this.algo = algo; }
Iterable sortImages(...) {
algo.sort(...);
}
}
interface ImagesSorterAlgo {
Iterable sort(...);
}
Now about your questions :
1) the "when" expression was invoked immediately. (not wanted)
It is expected imagesSorterSpy is a spy so by default it calls the real code. Instead you should use the alternate API, the same that #RobbyCornelissen showed. i.e.
doAnswer(sortWithFakeDate()).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
// with BDD aliases (BDDMockito) which I personnaly finds better
willAnswer(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
will(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
sortWithFakeDate() would a static factory method that returns the answer, so the code reads well, and maybe reused elsewhere.
2) eventually the callback wasn't call.
This issue is most probably due to non equal arguments. You may need to check the equals method. Or relax the stub using the any() matcher.
I don't know the types of the arguments and classes you're using, so I can't provide a complete example, but you can stub using callbacks with the Answer<T> interface:
Mockito.doAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
ImagesSorter mock = (ImagesSorter) invocation.getMock();
Object[] args = invocation.getArguments();
return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
fakeNowDate);
}
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

Why is Mockito giving me a new map instance?

I have a simple POJO that contains a Map<String,Widget> property:
private Map<String, Widget> widgetCache = new HashMap<String, Widget>();
#Override
public Logger newWidget(String name, Widget widget) {
// First, print the contents of widgetCache in pretty print format.
Map<String, Widget> map = widgetCache;
List<String> keys = new ArrayList<String>(map.keySet());
System.out.println("Printing..." + keys.size());
for (String key: keys)
System.out.println(key + ": " + map.get(key).getName());
if(!widgetCache.containsKey(name)) {
System.err.println("I don't contain " + name);
widgetCache.put(name, widget);
}
return widgetCache.get(name);
}
Simple enough: it just doesn't allow duplicate Widgets from being inserted into the map. When I go to test this in a JUnit test method using Mockito (1.9.5):
CachingWidgetFactory fixture = new CachingWidgetFactory();
// By the way, I get errors if I try to make this next line:
// HashMap<String,Widget> mockMap = Mockito.mock(HashMap<String,Widget>.class);
// How do I enforce generics here when defining a mock?
HashMap mockMap = Mockito.mock(HashMap.class);
fixture.setLoggerCache(mockMap);
fixture.newWidget("Widget-A", new Widget("Widget-A"));
fixture.newWidget("Widget-A", new Widget("Widget-A"));
Mockito.verify(mockMap, Mockito.times(1))
.put(Mockito.anyString(), Mockito.<Logger>any());
I get the test failing with the following JUnit output:
org.mockito.exceptions.verification.TooManyActualInvocations:
hashMap.put(<any>, <any>);
Wanted 1 time:
And in the (STDOUT) console output, I see this:
Printing...0
I don't contain Widget-A
Printing...0
I don't contain Widget-A
So it looks like the mock that Mockito is returning is allowing the 2nd (duplicate) insert. However, when I remove the Mockito mockMap entirely, and make the test method look like:
CachingWidgetFactory fixture = new CachingWidgetFactory();
fixture.newWidget("Widget-A", new Widget("Widget-A"));
fixture.newWidget("Widget-A", new Widget("Widget-A"));
Then in the console output, I get:
Printing...0
I don't contain Widget-A
Printing...1
Now the (non-mocked) code is correctly preventing the duplicate insert. So it's almost as if Mockito is returning a new HashMap every time newWidget is being called. What's going on here, and why? (And bonus points if you can help me on the generic issue mentioned above.) Thanks in advance.
That's a common mistake. You have to remember that you mocked HashMap. So, mockito is not giving you a new map everytime, it just don't know how to behave because you mocked the HashMap.
Giving that, it will behave as you tell it to behave. If you haven't said anything, it will return default values/do nothing when you call your methods. So, at the line
if (!widgetCache.containsKey(name))
because you didnt say how it should behave, it will return the default value of false. You can mock the map to return false at the second call using Mockito with something like
given(hashMap.containsKey(name)).willReturn(false, true);
With that, HashMap will return that "contains" the key at the second call of containsKey with the given name. You can read its documentation here
Another thing you could do is to give to it a real implementation of HashMap, but I prefer the "mock" way :)
EDIT
I gave the link to BDDMockito, but it works the same way with when->thenReturn. It's just syntax sugar :) I find it easier to read.
// How do I enforce generics here when defining a mock?
HashMap mockMap = Mockito.mock(HashMap.class);
Handling generics is much easier if you use the mockito annotations, e.g.
#Mock
HashMap<String, Widget> mockMap;
and then in your setup method:
MockitoAnnotations.init(this);
But to your problem, just use
HashMap<String, Widget> map=new HashMap<String, Widget>();
so that the test uses a real HashMap that behaves like one, since that is the thing you want to test. If you're going to mock all the HashMap operations yourself, chances are you are making some kind of mistake (like forgetting to mock a method).

Error received using easymock

I am working on a new project and they have been using EasyMock (v2.4), which I am not as familiar with. I need to be able to do the following, but no one has an answer. The current framework uses an BaseDao.class which I would like to mock out per the following example, but I get an error. I'm looking for some direction.
BaseDao baseDao = EasyMock.mock(BaseDao.class);
EasyMock.expect(baseDao.findByNamedQuery("abc.query"), EasyMock.anyLong()).andReturn(...);
EasyMock.replay(baseDao);
EasyMock.expect(baseDao.findByNamedQuery("def.query"), EasyMock.anyLong).andReturn(..);
EasyMock.replay(baseDao);
The error I'm getting is as follows...
java.lang.AssertionError:
Unexpected method call findByNamedQuery("def.query"):
findByNamedQuery("abc.query", 1): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:32)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:61)
at $Proxy5.findByNamedQuery(Unknown Source)
You are defining a replay(...) twice so only the first one will count. It's defined like this until you call reset(...).
To fix the problem, you can either:
1) Remove the invocation that is causing the test failure:
EasyMock.expecting(baseDao.findByNamedQuery("def.query"), EasyMock.anyLong)
.andReturn(...);
EasyMock.replay(baseDao);
2) Instead of defining a fixed string in your expectation, you can expect any string:
EasyMock.expecting(baseDao.findByNamedQuery((String)EasyMock.anyObject()),
EasyMock.anyLong).andReturn(...);
It looks like the test expected a method call with the parameter "abc.query" but the method was called with "def.query" instead.
Debugging the test step by step should help finding the problem.
If you are expecting findByNamedQuery to be called twice, then remove the 1st call to the replay method. It is only needed the once, after all you expectations for the test have been set.
BaseDao baseDao = EasyMock.mock(BaseDao.class);
EasyMock.expect(baseDao.findByNamedQuery("abc.query"), EasyMock.anyLong()).andReturn(...);
// Remove EasyMock.replay(baseDao);
EasyMock.expect(baseDao.findByNamedQuery("def.query"), EasyMock.anyLong).andReturn(..);
EasyMock.replay(baseDao);

Categories

Resources