Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerMock complains of incorrect arguments even though the private method is mocked

I was trying out PowerMock, and am trying to mock a private method like so:

expectPrivate(n, "doLogin", anyString(), anyString()).andReturn(true);

That is, I want true to be returned from doLogin irrespective of the parameters passed. The public method which delegates to this private method simply passes-on the arguments. Here is the definition of the class to be mocked:

class N {
        public boolean login(String username, String password) {
            return doLogin(username, password);
        }
        private boolean doLogin(String u, String p){
            //validate login
            //...
            //...
            return true;
        }
     }

And this is the test class where I am trying to invoke the mock:

import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.createPartialMock;
import static org.powermock.api.easymock.PowerMock.expectPrivate;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.verify;
import static org.mockito.Matchers.anyString;

import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

@RunWith(PowerMockRunner.class)
@PrepareForTest(N.class)
public class NodeAccessorTest {
private String username = "admin";
private String password = "asdf";

@Test
public void testMockLogin() throws Exception {
    N n = createPartialMock(N.class,
            "doLogin", String.class, String.class);
    boolean expected = true;
    expectPrivate(n, "doLogin", anyString(), anyString()).andReturn(expected);
    replay(n);
    boolean actual = n.login("A", "B");
    verify(n);
    assertEquals("Expected and actual did not match", expected, actual);
   }
}

This is the failure trace:

java.lang.AssertionError: 
  Unexpected method call N.doLogin("A", "B"):
    N.doLogin("", ""): expected: 1, actual: 0
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
    at org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl.invoke(EasyMockMethodInvocationControl.java:91)
    at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:124)
    at org.powermock.core.MockGateway.methodCall(MockGateway.java:185)
    at com.pugmarx.mock.N.doLogin(N.java)
    at com.pugmarx.mock.N.login(N.java:60)

So the mocking framework is not happy when specific Strings are passed to the public login() method, but fine when anyString is used. Ideally, I would expect that since the call to the private doLogin is mocked, this should not be the case. What am I missing?

like image 989
pugmarx Avatar asked May 07 '15 07:05

pugmarx


People also ask

What is difference between mock and PowerMock?

Both tools are “hiding away” the collaborators in the class under test replacing them with mock objects. The division of work between the two is that Mockito is kind of good for all the standard cases while PowerMock is needed for the harder cases. That includes for example mocking static and private methods.

Can private methods be mocked?

For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.

What is PowerMock in JUnit?

PowerMock is an open-source Java framework used for creating a mock object in unit testing. It extends other mocking frameworks such as EasyMock and Mockito to enhance the capabilities.


1 Answers

I had a similar issue and I think your problem can be in the Matchers anyString() passed by param to PowerMock expectPrivate method.

Based in your imports, you are using Mockito Matchers instead EasyMock Matchers: org.mockito.Matchers.anyString.

Could you try to changing the Matchers for the next: EasyMock.anyString()

import org.easymock.EasyMock;

...

expectPrivate(n, "doLogin", EasyMock.anyString(), EasyMock.anyString()).andReturn(expected);

Hope it helps.

like image 96
troig Avatar answered Oct 16 '22 22:10

troig