简体   繁体   English

在多线程环境中使用模拟对象

[英]Using mock objects in multithreaded environment

Starting with jMock 2.6 , I can make sure my mock objects are seen consistently by multiple threads viajMock 2.6开始,我可以确保通过多个线程一致地看到我的模拟对象

final Mockery mockery = new Mockery();
mockery.setThreadingPolicy(new Synchroniser());

What are my options (I'm experiencing intermittent test "flakes") when using jMock 2.5 ?使用jMock 2.5时,我有哪些选择(我遇到间歇性测试“碎片”)?

Particularly, is it sufficient ( update : no, doesn't play well with expectations ) to wrap all mock object method invocations using synchronized ?特别是,使用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 + 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. CGLib 将允许您代理类和接口,而不仅仅是像java.lang.reflect.Proxy这样的接口,并且 ObjenesisHelper 将允许您构造类的实例而无需调用构造函数。 See here for a CGLib example and here for a ObjenesisHelper example .请参阅此处的 CGLib 示例此处的 ObjenesisHelper 示例

Additionally you can unpack the InvocationTargetException to ensure that the proxy instance throws the expected Exception defined by the mocked class.此外,您可以解压InvocationTargetException以确保代理实例抛出由模拟类定义的预期Exception Finally, using registerStaticCallbacks will ensure that the bound method interceptor is present among all invoking threads.最后,使用registerStaticCallbacks将确保绑定的方法拦截器存在于所有调用线程中。

public <T> T createProxy(final Class<? extends T> classToMock, final T mock) {
    final MethodInterceptor interceptor = (object, method, args, proxy) -> {
        synchronized (mock) {
            try {
                return method.invoke(mock, args);
            } catch (final InvocationTargetException e) {
                if (e.getCause() != null) {
                    throw e.getCause();
                }
                throw e;
            }
        }
    };

    final Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(classToMock);
    final Set<Class<?>> interfaces = new LinkedHashSet<>();
    if (classToMock.isInterface()) {
        interfaces.add(classToMock);
    }
    interfaces.addAll(Arrays.asList(classToMock.getInterfaces()));
    interfaces.add(CaptureControl.class);
    enhancer.setInterfaces(interfaces.toArray(new Class[interfaces.size()]));
    enhancer.setCallbackType(interceptor.getClass());

    final Class<?> proxyClass = enhancer.createClass();
    Enhancer.registerStaticCallbacks(proxyClass, new Callback[] { interceptor });
    return (T) ObjenesisHelper.newInstance(proxyClass);
}

When using the above approach, what are my chances to run into any deadlocks?使用上述方法时,我遇到任何死锁的机会有多大?

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 synchronized will 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. synchronized的使用将确保在任何给定时间只有一个线程可以操作模拟实例......并且除非 jmock 将方法调用委托给一个单独的线程(据我所知它没有),那么代码应该正常执行而不是阻塞. If jmock requires you lock on all Mockery instances 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.如果 jmock 要求您一次锁定所有Mockery实例,那么您可以传入一个专用对象进行同步,或者为所有代理拦截器提供可重入锁以共享。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM