This code seems to do the trick. If I add a method to Foo and do not include it in FooWrapper, the test fails.
FooWrapper wrapper = new FooWrapper(delegate);
Foo delegate = Mockito.mock(Foo.class);
// For each method in the Foo class...
for (Method fooMethod : Foo.class.getDeclaredMethods()) {
boolean methodCalled = false;
// Find matching method in wrapper class and call it
for (Method wrapperMethod : FooWrapper.class.getDeclaredMethods()) {
if (fooMethod.getName().equals(wrapperMethod.getName())) {
// Get parameters for method
Class<?>[] parameterTypes = wrapperMethod.getParameterTypes();
Object[] arguments = new Object[parameterTypes.length];
for (int j = 0; j < arguments.length; j++) {
arguments[j] = Mockito.mock(parameterTypes[j]);
}
// Invoke wrapper method
wrapperMethod.invoke(wrapper, arguments);
// Ensure method was called on delegate exactly once with the correct arguments
fooMethod.invoke(Mockito.verify(delegate, Mockito.times(1)), arguments);
// Set flag to indicate that this foo method is wrapped properly.
methodCalled = true;
}
}
assertTrue("Foo method '" + fooMethod.getName() + "' has not been wrapped correctly in Foo wrapper", methodCalled);
}
The key line here which was missing in your code is
fooMethod.invoke(Mockito.verify(delegate, Mockito.times(1)), arguments);
It might look a little odd, but this works because it invokes things in the same order Mockito expects: first Mockito.verify(delegate)
is called (which internally starts the Mockito verification), then the method is invoked. A similar non-reflection invocation would look like Mockito.verify(delegate).foo()
. Use this 'why' to help adapt the code to different use cases without breaking how the test does verification.
One word of caution, I would add a check at the beginning of each of your loops which iterate over the result of getDeclaredMethods(). This method returns all methods whether they are public, private, protected etc. Attempting to access an inaccessible method throws an exception. You can use Method.isAccessible() to check for this.