1

如果我在运行时包装由 Mockito 创建的模拟,然后在包装器上调用一个方法,则不会调用包装的模拟。请看下面:

这是我运行的测试:

import static org.mockito.Mockito.verify;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
import org.junit.Test;
import org.mockito.Mockito;

public class MyTest {

    @Test
    public void mockIsCalled() {
        final Bar bar = Mockito.mock(Bar.class);
        final Bar wrapper = wrap(bar);
        wrapper.foo();
        verify(bar).foo();
    }

    @SuppressWarnings("unchecked")
    private <T> T wrap(final T objToWrap) {
        return (T) Enhancer.create(objToWrap.getClass(), NoOp.INSTANCE);
    }

}

其中 Bar 是:

public interface Bar {
    String foo();
}

测试失败,我得到的输出是:

java.lang.NoSuchMethodError: java.lang.Object.foo()Ljava/lang/String;
    at Bar$$EnhancerByMockitoWithCGLIB$$d2b59df8.foo(<generated>)
    at MyTest.mockIsCalled(MyTest.java:18)
...

如果我将 Bar 变成一个类,如下所示:

public class Bar {

    public String foo() {
        System.out.println("foo");
        return null;
    }

}

测试继续失败,foo打印在控制台上,我得到输出:

Wanted but not invoked:
bar.foo();
-> at MyTest.mockIsCalled(MyTest.java:20)
Actually, there were zero interactions with this mock.

    at MyTest.mockIsCalled(MyTest.java:20)
...

我很困惑。

我要解决的真正问题是包装动态代理(由 Mule 通过组件绑定注入),以便记住对包装的动态代理的方法调用。我想让它足够通用,这样就足以包装动态代理对象而无需扩展任何接口。

谢谢

4

1 回答 1

1

您在 Bar 类的情况下看到的问题,如果不是因为 cglib 古怪,您也会在接口版本中看到。您不是在包装模拟,而是在创建一个新对象。因此,原始模拟从未被执行过。

对于使用类版本,您是否尝试过create()接受接口作为参数的版本?

我不确定我是否完全了解您的使用场景,但是对于特定于 Mockito 的东西,您可以尝试使用 cglib 创建的代理,然后spy()在其上使用,而不是模拟一个新对象。

坦率地说,我对 cglib 了解不多,但也许你可以实现你自己的Callback,它包含并委托给原始对象。你可以提供那个CallbackEnhancer.create()代替那个NoOp

于 2012-12-08T20:43:30.410 回答