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

标签 java multithreading unit-testing concurrency jmock

jMock 2.6开始,我可以确保多个线程一致地看到我的模拟对象

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

使用jMock2.5时我有哪些选择(我遇到间歇性测试“碎片”)?

特别是,使用 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);
                }
            });
}

使用上述方法时,遇到死锁的机会有多大?

最佳答案

您是否考虑过使用 CGLib + ObjenesisHelper? CGLib 将允许您代理类和接口(interface),而不仅仅是像 java.lang.reflect.Proxy 这样的接口(interface),并且 ObjenesisHelper 将允许您构造类的实例,而无需调用构造函数。 请参阅here for a CGLib examplehere for a ObjenesisHelper example

此外,您还可以解压 InitationTargetException 以确保代理实例抛出模拟类定义的预期 Exception。最后,使用registerStaticCallbacks将确保绑定(bind)方法拦截器存在于所有调用线程中。

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?

我不认为您提供的解决方案或上面建议的解决方案会遇到任何死锁(假设您的代码中不存在死锁)。。使用synchronized将确保在任何给定时间只有一个线程可以操作模拟实例..并且除非jmock将方法调用委托(delegate)给一个单独的线程(据我所知,它不会) 那么代码应该正常执行而不是阻塞。如果 jmock 要求您立即锁定所有 Mockery 实例,那么您可以传入一个专用对象进行同步,或者为所有代理拦截器提供可重入锁以共享。

关于java - 在多线程环境中使用模拟对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51965601/

相关文章:

java:中断线程是绝对必要的

java - 使用 Java 测试平面文件内容和格式

java - 启动两个 Junit 测试套件

c# - 在 C# 或 Java 中子类化时是否可以覆盖私有(private)成员?

java - java中的回调行为

java - J2Objc 类型项目的设计模式

java - 文本字段使用卡片布局丢弃先前输入的值

c# - TCP 服务器 CPU 使用率高

java - 减少 Java 中同步块(synchronized block)的范围意外地损坏了我的 ArrayList,为什么会出现这种情况?

asp.net-mvc - 在对 Controller 操作进行单元测试时提供明确的 View 名称?