7

I am trying to mock a private method and verify it has been executed.
The mocking itself works fine, that is I am getting correct results whether I comment/uncomment the 'when' line. However, I am having troubles with verification.

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class TestClass {

    @Test
    public void test() throws Exception {
        ClassToTest spy = PowerMockito.spy(new ClassToTest());
        when(spy, method(ClassToTest.class, "privMethod", int.class)).withArguments(anyInt()).thenReturn(20);
        System.out.println(spy.pubMethod());
        PowerMockito.verifyPrivate(spy, times(1)).invoke("privMethod", int.class);
    }
}

class ClassToTest {

    public int pubMethod() {
        return privMethod(231);
    }

    private int privMethod(int whatever) {
        return 10;
    }
}

created this example based on https://code.google.com/p/powermock/wiki/MockitoUsage13 This is what I am getting, any idea why?

java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1873)
    at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:773)
    at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:638)
    at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
    at org.powermock.api.mockito.internal.verification.DefaultPrivateMethodVerification.invoke(DefaultPrivateMethodVerification.java:39)
    at test.TestClass.test(TestClass.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:69)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:128)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:283)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:91)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:123)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:104)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.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:684)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:391)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Łukasz
  • 1,980
  • 6
  • 32
  • 52
  • 2
    If you want to *test* `ClassToTest`, why are you mocking it? You should be mocking the *dependencies* of `ClassToTest`. That's the point. – Jon Skeet Oct 09 '14 at 10:31
  • @Jon Skeet I guess OP is just learning the PowerMockito mechanisms. The example works for that. – Ray Oct 09 '14 at 10:39
  • @Ray: Possibly... but it still feels like an abuse of mocking to me. Ah well. – Jon Skeet Oct 09 '14 at 10:42
  • @Jon Skeet: How does it abuse mocking. The private method makes a use of some third party code that doesn't work in Junit environment, how am I supposed to test it otherwise than mocking? – Łukasz Oct 09 '14 at 10:48
  • 2
    @Łukasz: You'd usually make that dependency available separately, so you could mock (or fake) *just the dependency* instead of mocking a private method, which is meant to be an implementation detail. It's hard to give more concrete information without knowing about the third party library in question or what you're doing with it, but effectively you want to make the "seam" between your code and the third party code more easily replacable. Just my opinion, of course - but I'd far rather inject a fake implementation of dependency than mock out private methods, leaving a brittle test. – Jon Skeet Oct 09 '14 at 10:51

1 Answers1

7

Instead of int.class, verify the argument value 231. Mock verification works by matching values, not types (unless you use the argument matchers as in your when part).

Ray
  • 3,084
  • 2
  • 19
  • 27
  • Test passes now, however when I change times(1) to any other value I am getting: org.powermock.reflect.exceptions.TooManyFieldsFoundException: Two or more fields matching type java.lang.String. which doesn't seem to be reflecting invalid number of expected calls. – Łukasz Oct 09 '14 at 10:45