编辑:现在这是Powermock的问题:http://code.google.com/p/powermock/issues/detail?id=449&thanks=449&ts=1371519268
我正在使用EasyMock测试一些代码,它调用一个返回ArrayListMultimap的方法,我不想去构造一个充满模拟的集合对象,所以我决定简单地模拟ArrayListMultimap并让它返回无论我想在标准的模拟对象中获得什么样的模拟。 ArrayListMultimap原来是最终的,所以我在它上面扔了一些PowerMock pixy灰尘。但是,当我运行我的测试时,我得到了:
java.lang.StackOverflowError
at java.lang.reflect.Method.copy(Method.java:143)
at java.lang.reflect.ReflectAccess.copyMethod(ReflectAccess.java:118)
at sun.reflect.ReflectionFactory.copyMethod(ReflectionFactory.java:282)
at java.lang.Class.copyMethods(Class.java:2757)
at java.lang.Class.getDeclaredMethods(Class.java:1793)
at org.easymock.internal.BridgeMethodResolver.getAllDeclaredMethods(BridgeMethodResolver.java:434)
at org.easymock.internal.BridgeMethodResolver.findBridgedMethod(BridgeMethodResolver.java:78)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:87)
at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>)
at org.easymock.internal.ExpectedInvocation.matches(ExpectedInvocation.java:85)
at org.easymock.internal.UnorderedBehavior.addActual(UnorderedBehavior.java:57)
at org.easymock.internal.MocksBehavior.addActual(MocksBehavior.java:87)
at org.easymock.internal.ReplayState.invokeInner(ReplayState.java:58)
at org.easymock.internal.ReplayState.invoke(ReplayState.java:46)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:40)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:85)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:94)
at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>)
at org.easymock.internal.ExpectedInvocation.matches(ExpectedInvocation.java:85)
at org.easymock.internal.UnorderedBehavior.addActual(UnorderedBehavior.java:57)
at org.easymock.internal.MocksBehavior.addActual(MocksBehavior.java:87)
at org.easymock.internal.ReplayState.invokeInner(ReplayState.java:58)
at org.easymock.internal.ReplayState.invoke(ReplayState.java:46)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:40)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:85)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:94)
at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>)
at org.easymock.internal.ExpectedInvocation.matches(ExpectedInvocation.java:85)
at org.easymock.internal.UnorderedBehavior.addActual(UnorderedBehavior.java:57)
at org.easymock.internal.MocksBehavior.addActual(MocksBehavior.java:87)
at org.easymock.internal.ReplayState.invokeInner(ReplayState.java:58)
at org.easymock.internal.ReplayState.invoke(ReplayState.java:46)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:40)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:85)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:94)
at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>)
at org.easymock.internal.ExpectedInvocation.matches(ExpectedInvocation.java:85)
at org.easymock.internal.UnorderedBehavior.addActual(UnorderedBehavior.java:57)
at org.easymock.internal.MocksBehavior.addActual(MocksBehavior.java:87)
at org.easymock.internal.ReplayState.invokeInner(ReplayState.java:58)
at org.easymock.internal.ReplayState.invoke(ReplayState.java:46)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:40)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:85)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:94)
at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>)
at org.easymock.internal.ExpectedInvocation.matches(ExpectedInvocation.java:85)
at org.easymock.internal.UnorderedBehavior.addActual(UnorderedBehavior.java:57)
最终我将问题提炼到这个例子:
import com.google.common.collect.ArrayListMultimap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.easymock.EasyMock.expect;
@RunWith(PowerMockRunner.class)
@PrepareForTest(ArrayListMultimap.class)
public class PurePowermockTest {
@Test
public void testPowerMockVsGuava() {
ArrayListMultimap map = PowerMock.createMock(ArrayListMultimap.class);
expect(map.put("foo", "bar")).andReturn(true);
PowerMock.replay(map);
map.put("foo", "bar"); // SOError!
}
}
上面的例子当然没有测试任何东西,map.put()调用通常会在我正在测试的某个方法中。此代码只是为了尽可能简洁地演示问题。我也知道我可以构建ArrayListMultiMap并返回它,但是把它放在一边,模拟地图也应该有效。我很确定这是一个在powermock中的错误,但我的问题是:
我是否正确使用PowerMock?这应该有用吗,还是有什么我错过了PowerMock的功能或正确用法?我正在使用EasyMock.expect方法,但我没有看到PowerMock上的等价物,所以我认为这没问题......
答案 0 :(得分:1)
看起来像PowerMock中的一个错误(或者用于字节码操作的javassist)。由于我正在使用PowerMock和Mockito(即PowerMockito),我已经检查过它是否可以与Mockito重现 - 而且确实如此。鉴于测试:
@PrepareForTest(ArrayListMultimap.class)
public class PowerMockitoTest {
@Rule // used instead @RunWith(PowerMockRunner.class) in newer version of JUnit
public PowerMockRule rule = new PowerMockRule();
@Test
public void testPowerMockitoVsGuava() {
final ArrayListMultimap<String, String> mock =
PowerMockito.mock(ArrayListMultimap.class);
PowerMockito.when(mock.put("foo", "bar")).thenReturn(true);
Assert.assertTrue(mock.put("foo", "bar")); // SOError!
}
}
它仍然在代理的ArrayListMultimap类中生成SO并指向等于(stacktrace中的at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>)
)。
这个特殊的bug可能与重复出现issue 88有关 - 当equals是final时(但在ArrayListMultimap中它不是......)或者在其中使用getClass()时它会提到SO错误(它没有,另一方面使用instanceof)或从equals调用另一个方法(这可能是一个例子,因为asMap()
在AbstractMultimap#equals
内调用。另一方面,我检查了LinkedListMultimap
哪个适用于PowerMock,因此它可能是ArrayListMultimap
类型层次结构(扩展AbstractMultimap
- &gt; AbstractMapBasedMultimap
- &gt; {{ 1}}而AbstractListMultimap
没有)。
不幸的是,我不知道PowerMock的内部结构,也没有找到具体的内容,因此您应该通过Google Group联系PowerMock开发人员。
回到你的问题 - 如果你可以改变你的方法返回LinkedListMultimap
,那么你很好 - 你应该在接口上操作而不是具体的实现(你甚至不必使用PowerMock) )。 ListMultimap
也是一个选项。