PowerMockito. Use of whenNew() to return a mock causes "Arguments are different" when verifying a method of that mock.

6,641 views
Skip to first unread message

Carlos Rodriguez Garcia

unread,
Dec 25, 2011, 12:30:07 PM12/25/11
to powe...@googlegroups.com
Hi,

I'm unit testing a method that creates a new object and then uses some methods of it. When I stub the constructor with PowerMockito to return a mock of the new object everything seems to be going fine since the constructor verifying passes, but when I try to verify the use of a method of the mock object I get a "Argument(s) are different!" message, although both the wanted invocation and the actual invocation calls the same method (SomeObject.someMethod() ). I have spent a few hours in this issue and can't really find what is going wrong, would appreciate a little help on this matter :)

The method I'm testing implements a step movement following the direction pointed in a compass, uses an instance of a Coordinates object, clones it with a constructor, and then calculates the new Coordinates depending of the cardinal direction.
I've tried to stubb the constructor in every way I could think off, with no better results.

The JUnit test in construction:


some imports

@RunWith(PowerMockRunner.class)
@PrepareForTest( { Compass.class, Coordinates.class } )

public class CompassTest {
@Test
public void testMoveFollowingDirection() throws Exception {
// stub
Coordinates mockedCoordinates = PowerMockito.mock(Coordinates.class);
PowerMockito.whenNew(Coordinates.class).withArguments(any(Coordinates.class)).thenReturn(mockedCoordinates);

// call
Compass.NORTH.moveFollowingDirection(any(Coordinates.class));

// verifying, this one passes
PowerMockito.verifyNew(Coordinates.class).withArguments(any(Coordinates.class));
// this one don't
Mockito.verify(mockedCoordinates).decrementYCoordinate();
}
}


The relevant code of both classes:

public enum Compass() {
NORTH, EAST, SOUTH, WEST;

public Coordinates moveFollowingDirection(Coordinates currentPosition) {
// clones the currentPosition
Coordinates positionSteppingInto = new Coordinates(currentPosition);

if (ordinal() == 0) {
positionSteppingInto.decrementYCoordinate();
}
else if ()
(...)
}


public class Coordinates() {
private things

public Coordinates(Coordinates coordinates) {
this(coordinates.getXcoordinate(), coordinates.getYcoordinate());
}

public final void decrementYCoordinate() {
(...)
}
(...)
}

The throws:
Argument(s) are different! Wanted:
game.Coordinates.decrementYCoordinate();
-> at org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:291)
Actual invocation has different arguments:
game.Coordinates.decrementYCoordinate();
-> at org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl$2.<init>(MockitoMethodInvocationControl.java:258)

    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:291)
    at org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:193)
    at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)
    at org.powermock.core.MockGateway.methodCall(MockGateway.java:168)
    at game.Coordinates.decrementYCoordinate(Coordinates.java)
    at unit.CompassTest.testMoveFollowingDirection(CompassTest.java:79)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:307)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)


Thanks for your time, and Merry Christmas everyone!!

Carlos Rodriguez Garcia

unread,
Dec 28, 2011, 3:26:01 PM12/28/11
to powe...@googlegroups.com
Hi,

Found the issue for myself. It happens that the class Coordinates overrides both equals() and hashCode() methods, and that they were declared as final. Once the final modifier was removed from those two methods everything worked as expected, or so I think.

It took me a few hours of "why Jesus? why is this not working? :'( " staring at the test code, until I left it behind and started another test that also needed to mock the class Coordinates. It didn't work either, but threw a different error that gave me the answer at the first Google search. Overriden methods such as equals and hashCode that are also declared as final are not of the liking of PowerMock, for now. Lesson learned!

Thanks for your time, and thanks you guys for developing this great tool!
Reply all
Reply to author
Forward
0 new messages