10

I have a spy or a mock of an object and I wants to verify that a method has been call problem, I receive methodname at execution Time not compilation time

I would like to do something like:

  SimpleObj mockObject= Mockito.mock(SimpleObj.class);
  Class myClass = SimpleObj.class;
  Method meth = myClass.getMethod("getGuid");

  Mockito.verify(meth.invoke(mockObject));

I have made a kind of workaround using

MockingDetails mockingDetails = Mockito.mockingDetails(mockObject);

Collection<Invocation> invocations = mockingDetails.getInvocations();

List<String> methodsCalled = new ArrayList<>();
for (Invocation anInvocation : invocations) {
  methodsCalled.add(anInvocation.getMethod().getName());
}
assertTrue(methodsCalled.contains("getGuid");

Problem it works until I use PowerMockito : for standard method it works but if the method is final, the method is not present in mockingDetails.getInvocations() (but even if not present in mockingDetails.getInvocations() the real verify(mock).getGuid() works in a good way

So if you have any idea/advice it would be glad

Regards

Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72
Guillaume B.
  • 133
  • 1
  • 7
  • 1
    This is a total abuse of the syntax, but does `meth.invoke(Mockito.verify(mockObject))` work? – Jeff Bowman Aug 25 '15 at 17:27
  • Thx for this idea Unfortunately, It does nothing : I can call or not the getGuid method before, but the line don't seems to have any effect – Guillaume B. Aug 27 '15 at 07:58
  • meth.invoke(Mockito.verify(mockObject)) would be more correct, as with Mockito.verify(meth.invoke(mockObject)); you're passing not a mock object but results of the execution. Though I can't make it working, ether... – Tatiana Goretskaya Feb 06 '19 at 20:50
  • Make sure you're getting the `Class` object from PowerMock or Mockito. Just using SimpleObj.class, it will see that the method is final, and not return the reference to the stubbed one. – Daniel Apr 24 '20 at 15:06

2 Answers2

2

This works for me using regular Mockito (I use this to verify that the hidden method "refresh()" in android.bluetooth.BluetoothGatt is invoked:

private void assertMethodInvoked(@NonNull Object object,
                                 @NonNull String methodName,
                                 @NonNull VerificationMode verificationMode) throws Exception {
    final Method method = object.getClass().getDeclaredMethod(methodName);
    final Object verify = verify(object, verificationMode);
    method.invoke(verify);
}
Alix
  • 2,630
  • 30
  • 72
0

I actually made this work using reflection... I could not use the matchers but I've got the original parameters. My test verifies that an intermediate proxy and data convertion process invokes the real implementation:

private void assertMethodExecuted(String testName, Object ...params) throws Exception {
    assertManagerMethodExecuted(getMethodName(testName), params);
}

private void assertManagerMethodExecuted(String methodName, Object[] params) throws Exception {
    MiGRPCManagerImpl manager = Whitebox.getInternalState(server, MiGRPCManagerImpl.class);
    Method method = Arrays.stream(manager.getClass().getMethods())
        .filter(each -> each.getName().equals(methodName))
        .findFirst()
        .orElse(null);
    MiGRPCManagerImpl verify = Mockito.verify(manager, new VerificationMode() {

        @Override
        public void verify(VerificationData data) {
            assertEquals(1, data.getAllInvocations().size());
            data.getAllInvocations().get(0).getMethod().equals(method);
        }

        @Override
        public VerificationMode description(String description) {
            return this;
        }
    });

    if (params.length == 0) {
        method.invoke(verify);
    } else if (params.length == 1) {
        method.invoke(verify, params[0]);
    } else {
        method.invoke(verify, params);
    }

}

private String getMethodName(String testName) {
    return testName.substring(testName.indexOf("_") + 1, testName.length());
}

and a test goes like this:

@Test
public void test_disconnectFromGui() throws SecurityException, Exception {
    String ip = factory.newInstance(String.class);
    String userName = factory.newInstance(String.class);
    fixture.disconnectFromGui(userName, ip );
    assertMethodExecuted(new Object() {}.getClass().getEnclosingMethod().getName(), userName, ip );
}
eduyayo
  • 2,020
  • 2
  • 15
  • 35