Error received using easymock - java

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);

Related

Do I always need `when/thenReturn` for mock object's functions

I am writing a test in Scala where I do something like this --
val svc = mock[Service]
Initializer.fun1(svc)
fun1 internally calls a function svc.fun2 which returns Unit.
My test is failing when it tries to execute svc.fun2 with this error -
java.lang.NoSuchMethodError: org.mockito.internal.invocation.ArgumentsProcessor.expandArgs
As svc has already been mocked, I shouldn't have to mock fun2 ,right ?
Unless I want fun2 to return a specific value
Same thing worked for another codebase of mine, but that's using a different library for Mockito
Update :
I also tried adding a when/thenReturn for fun2 but still getting the same error.
I just did this
when(svc.fun2()) thenReturn()
since it's supposed to return UNIT

jmockit verifications block throwing Missing 1 invocation to methodName

Am trying to run one test case which will update the data into DB. This is my source code of test method.
#Tested // This is class-level scope as I have different test methods.
FirstLevelClass firstLevelClass;
#Test
public void testUpdateDB(#Mocked SecondLevelClass secondLevelClass) throws Exception {
// Updated method by passing an argument.
firstLevelClass.updateDatabaseThroughSecondLevelClass(info);
new Verifications() {{
SecondLevelClass.updateDB(creds, data);
times =1;
}};
Here my intention is to verify the expected invocations to mocked methods[which recorded in expectations]. But, verifications block is giving the following exception message. If I remove times=1, then test case is getting success. That is not my desired result.Can anyone please suggest me what could be wrong in my test case.
mockit.internal.MissingInvocation: Missing 1 invocation to:
SecondLevelClass#updateDB(creds, data)
with arguments: creds, data
Caused by: Missing invocations
Updated Question :
There is one argument to updateDatabaseThroughSecondLevelClass(info), from that argument we are forming creds reference in SecondLevelClass.
Credentials creds = info.getCredentials();
But in verifications block[Which is part of FirstLevelClass] we have created locally test object.
Credentials creds = getCredsTestObject();
This is the reason why it complained about Missing invocations. Because both are two different references in two classes. Can anyone please suggest me how to handle this case.
Thanks In Advance.
It is a known issue in the integration between TestNG and JMockit: https://github.com/jmockit/jmockit1/issues/337

best solution for mocking chained calls in Java

I have the following code:
handler = NodeHandler.getINodeHandler(localZone).getITspPlatformHandler().getITspProcessorManagementHandler();
I mocked this out this way:
mockStatic(NodeHandler.class);
INodeHandler iNodeHandler = mock(INodeHandler.class,Mockito.RETURNS_DEEP_STUBS);
when(NodeHandler.getINodeHandler(localZone)).thenReturn(iNodeHandler);
ITspProcessorManagementHandler iTspProcessorManagementHandler =mock(ITspProcessorManagementHandler.class,Mockito.RETURNS_DEEP_STUBS);
when(iNodeHandler.getITspPlatformHandler().getITspProcessorManagementHandler()).thenReturn(iTspProcessorManagementHandler);
After a few row of code an another chained method call comes:
ITspTrafficProcessor processor = NodeHandler.getINodeHandler(localZone, localUI).getITspPlatformHandler().getITspProcessorManagementHandler()
.getITspProcessorHandler(procs[i]).getITspTrafficProcessorHandler(0).getAttributes();
And i mocked this out this way:
when(NodeHandler.getINodeHandler(localZone,UI.CORBA)).thenReturn(iNodeHandler);
when(iNodeHandler.getITspPlatformHandler().getITspProcessorManagementHandler()(+1+).getITspProcessorHandler(anyString())
.getITspTrafficProcessorHandler(anyInt()).getAttributes()).thenReturn(null);
So my question is that, i can not find a better solution than this, because the problem is if i tell the mockito to return null to the handler instead of iTspProcessorManagementHandler then i get a nullpointer exception at (+1+), but if i do the following changes to my code:
INodeHandler iNodeHandler = mock(INodeHandler.class,Mockito.RETURNS_MOCKS);
Than mockito mocks out every method call, and my when-thenReturn statements does not returns what i want for example null. So any advice to do a better solution????
Messy mocking like that is an indication that you could improve abstraction. I'd consider encapsulating that particular logic in a helper interface/class, or to inject the expected type returned by the "trainwreck" to the method/class.

EasyMock JUnit testing throws error on the setter method

I am using easyMock for JUnit testing. I want to test a method which gets a Project object as its arguments and sets the modify date of that project and persists it in db.
So e.g.
public void setProject(Project project) {
project.setModifyDate(new Date());
this.reporsitory.persist(project);
}
Now at my test method I have tow mocked projects. For one of them I have set the return value of the getModifyDate. For the other mocked project object I just call the setProject(mockedProject); Now I assertEqual these two project objects.
The problem is easymock throws me an error at the project.setModifyDate(new Date()) of the class which I am testing.
Exception : Unexpected method call project.setModifyDate(..).. Expected:1, Actual:0.
It seems that it does not expect the setter method. Could you please let me know what I am doing wrong.
Thanks.
Yes, it is because of the type of mock object you created. It expects your code to call every method you defined when the one call executes. I cannot remember the exact name but i think it is something like nicemock, versus a strictmock whick makes your code execute every expected method. You should use EasyMock.createNiceMock() for your mock object. The error you have is because it expects you to call setModifyDate but your code didn't for that call.
Your call is unexpected because you must have not put EasyMock.expected for that method. You need to add your mock object .expected(getMethod).andReturns(something).

How to verify multiple method calls with different params

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)

Categories

Resources