Is it possible to add an interceptor to all answers when using Mockito?

Suppose I have a check annotation on my interface method to check the input arguments and return value. Is it possible at the moment (V 1.9.5) to tell Mockito to call this validator during the call process?

The background would have been to prohibit developers from writing unrealistic tests, making fun of this interface in a way that violates the specified validator.

So I would like to register something like

class MyAnswerInterceptor<T> implements AnswerInterceptor<T> { @Override public Answer<T> intercept(final Answer<T> answer) { return new Answer<T>() { @Override public T answer(InvocationOnMock invocation) throws Throwable { validateArguments(invocation); T result = answer.answer(invocation); validateReturnValue(result); return result; } } } } 

to call each response of this layout. Is it even possible? I looked at the code and also check if I can hack at some point (even using reflection or the like), but it seems that due to the intricacy of creating the instance and the logic, it is hardly possible to achieve what I want (i.e. things like MockHandler mockHandler = new MockHandlerFactory().create(settings); make it impossible to capture and add custom things from above without fixing and deploying all this ...)

Any insight would be much appreciated :-)

+6
source share
1 answer

You could achieve this by creating MockMaker .

MockMaker is an extension point that allows you to use custom dynamic proxies and avoid using the default cglib / asm / objenesis implementation

Our custom implementation delegates all complex stuff to the default MockMaker : CglibMockMaker . It only decorates the createMock method by registering with the settings a InvocationListener parameter. This listener will be notified when an invocation been performed, allowing validateArguments and validateReturnValue to be used to call.

 import org.mockito.internal.creation.CglibMockMaker; import org.mockito.invocation.Invocation; import org.mockito.invocation.MockHandler; import org.mockito.listeners.InvocationListener; import org.mockito.listeners.MethodInvocationReport; import org.mockito.mock.MockCreationSettings; import org.mockito.plugins.MockMaker; public class ValidationMockMaker implements MockMaker { private final MockMaker delegate = new CglibMockMaker(); public ValidationMockMaker() { } @Override public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) { settings.getInvocationListeners().add(new InvocationListener() { @Override public void reportInvocation(MethodInvocationReport methodInvocationReport) { Invocation invocation = (Invocation) methodInvocationReport.getInvocation(); validateArguments(invocation.getArguments()); validateReturnValue(methodInvocationReport.getReturnedValue()); } }); return delegate.createMock(settings, handler); } @Override public MockHandler getHandler(Object mock) { return delegate.getHandler(mock); } @Override public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) { delegate.resetMock(mock, newHandler, settings); } protected void validateArguments(Object... arguments) { // Arrays.stream(arguments).forEach(Objects::requireNonNull); } private void validateReturnValue(Object result) { // Objects.requireNonNull(result); } } 

Last but not least, we need to tell Mockito to use our implementation. This can be done by adding a file.

 mockito-extensions/org.mockito.plugins.MockMaker 

containing our MockMaker class name:

 ValidationMockMaker 

See the Using the extension point section in javadoc.

+2
source

Source: https://habr.com/ru/post/948417/


All Articles