2013-06-17 4 views
2

EDIT: Это теперь подается как вопрос с Powermock здесь: http://code.google.com/p/powermock/issues/detail?id=449&thanks=449&ts=1371519268PowerMock StackOveflowError на ArrayListMultimap

я испытывал некоторый код, используя EasyMock, который вызывает метод, который возвращает ArrayListMultimap, и я не хочу идти к проблеме создания объекта коллекции, полного издевок, поэтому я решил просто издеваться над ArrayListMultimap и заставить его возвращать любые макеты, которые мне нужны в стандартном mock-объекте fasion. ArrayListMultimap оказывается окончательным, поэтому я выбросил на него пылевидную пыль PowerMock. Однако, когда я пробежал тест, который я получил:

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, поэтому я предполагаю, что это нормально ...

ответ

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! 
    } 

} 

он все еще производит SO и указывает на равных в классе проксируемого ArrayListMultimap в (at com.google.common.collect.ArrayListMultimap$$EnhancerByCGLIB$$2dd82dd1.equals(<generated>) в StackTrace).

Эта конкретная ошибка может быть связана с повторяющимся issue 88 - она ​​упоминает ошибки SO, когда equals является окончательным (но в ArrayListMultimap это не ...) или использует getClass() в нем (это не так, использует instanceof on с другой стороны) или вызывает другой метод из равных (это может быть здесь, так как asMap() вызывается внутри AbstractMultimap#equals). С другой стороны, я проверил LinkedListMultimap, который отлично работает с PowerMock, поэтому может быть что-то с ArrayListMultimap иерархией типов (продолжается AbstractMultimap ->AbstractMapBasedMultimap ->AbstractListMultimap пока LinkedListMultimap не делает).

К сожалению, я не знаю внутренних компонентов PowerMock и не нашел ничего конкретного, поэтому вам следует обратиться к разработчикам PowerMock, возможно, через Google Group.


Вернуться к вашей проблеме - если вы можете изменить способ вернуть ListMultimap, то вы хорошо - вы должны работать на интерфейсе, а не конкретной реализации в любом случае (и вы даже не должны использовать PowerMock). LinkedListMultimap также вариант здесь.

+1

Это хорошее подтверждение того, что это сила. Я зарегистрировал это как проблему здесь: http://code.google.com/p/powermock/issues/detail?id=449&thanks=449&ts=1371519268 – Gus

Смежные вопросы