Starting with jMock 2.6, I can make sure my mock objects are seen consistently by multiple threads via
final Mockery mockery = new Mockery();
mockery.setThreadingPolicy(new Synchroniser());
What are my options (I'm experiencing intermittent test "flakes") when using jMock 2.5?
Particularly, is it sufficient (update: no, doesn't play well with expectations) to wrap all mock object method invocations using synchronized?
<T> T synchronizedMock(final T mock,
final Class<T> clazz) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[] {clazz, CaptureControl.class},
(proxy, method, args) -> {
synchronized (mock) {
return method.invoke(mock, args);
}
});
}
When using the above approach, what are my chances to run into any deadlocks?
Have you looked into using CGLib + ObjenesisHelper? CGLib will allow you to proxy both classes and interfaces instead of just interfaces like
java.lang.reflect.Proxy, and ObjenesisHelper will allow you to construct an instance of a class without having to invoke a constructor. See here for a CGLib example and here for a ObjenesisHelper example.Additionally you can unpack the
InvocationTargetExceptionto ensure that the proxy instance throws the expectedExceptiondefined by the mocked class. Finally, usingregisterStaticCallbackswill ensure that the bound method interceptor is present among all invoking threads.I do not believe the solution you provided, nor the suggested solution above should run into any deadlocks (assuming that there are no deadlocks already present in your code). The use of
synchronizedwill ensure that only one thread will can manipulate the mock instance at any given time.. and unless jmock delegates method invocation to a separate thread (which to my knowledge it does not) then the code should execute normally and not block. If jmock requires you lock on allMockeryinstances at once then you could pass in a dedicated object to synchronize on, or provide a Re-entrant lock for all proxy interceptors to share.