2012-04-25 17 views
10

El método Quiero prueba tiene un bucle con la lógica para cada elemento en ListaB:Mockito ClassCastException

class A { 
    void someMethod(){ 

     for(B b: bList){ 
      //some logic for b 
     } 
    } 
} 

puedo obtener una excepción cuando la ejecución de prueba siguiente:

@RunWith(MockitoJUnitRunner.class) 
class ATest { 

    @Mock 
    private B b; 

    @Mock 
    private Map<Int, List<B>> bMap; 

    @Mock(answer = Answers.RETURNS_DEEP_STUBS) 
    private List<B> bList; 

    @Spy 
    @InjectMocks 
    private C c; 
    .... 

    @Test 
    public void test(){ 

     //this line executes fine 
     when(bList.size()).thenReturn(1); 

     //strangely this works fine 
     when(bMap.get(any())).thenReturn(bList); 

     //ClassCastException 
     when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b); 

     c.methodIWantToTest(); 
    } 
} 

La excepción consigo es:

java.lang.ClassCastException: 
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B

¿Alguien ha encontrado esto antes y ha encontrado una solución?

He buscado una solución y he encontrado algunos enlaces: http://code.google.com/p/mockito/issues/detail?id=251 y http://code.google.com/p/mockito/issues/detail?id=107

+0

Puede ser un problema existente como se ha señalado en los enlaces. –

+2

¿Realmente está tratando de burlarse de List and Map o simplemente para ilustrar el problema? ¿Por qué no utiliza una implementación de ArrayList y HashMap e inyecta esos? – jhericks

+0

@jhericks Sí, tiene razón, debería cambiar a la implementación de ArrayList y HashMap. Gracias –

Respuesta

18

Como this link you posted indica, le ha surgido un error con Answers.RETURNS_DEEP_STUBS.

En realidad, no veo ningún motivo para utilizar RETURNS_DEEP_STUBS en su código de ejemplo. Realmente deberías tratar de evaluar si necesitas o no tocones profundos, porque, como el Mockito docs say, "cada vez que un simulacro devuelve un simulacro muere un hada". Entonces, si puedes, simplemente sácalo y tu ejemplo funcionará.

Sin embargo, si insistes en el uso de stubs profundos, puedes solucionar este error mediante la conversión del valor devuelto de la llamada al método Object. Por ejemplo, reemplace la línea en cuestión en su código con esto:

when((Object)bList.get(0)).thenReturn(b); 

dicho todo esto, estoy muy de acuerdo con @jhericks. La mejor solución es, probablemente, utilizar un ArrayList real que contiene su simulacro en lugar de burlarse de List. El único problema es obtener su lista inyectada, por lo que tendría que usar @Spy. Por ejemplo:

@RunWith(MockitoJUnitRunner.class) 
class ATest{ 
    private B b = mock(B.class); 
    @Spy 
    private List<B> bList = new ArrayList<B>() {{ add(b); }}; 

    @InjectMocks 
    private C c = new C(); 

    @Test 
    public void test(){ 
    c.methodIWantToTest(); 
    // verify results 
    } 
} 
+0

Intenté ambas alternativas y ambas funcionan. Veo el caso como se indica en los documentos de Mockito y me abstendré de usar simulacros para devolver los simulacros. Gracias. –

1

En realidad, yo buscaría cuestiones de classpath y relaoding. En la lista de correo y en los rastreadores de problemas de mockito, algunos problemas informados podían rastrearse hasta classpath incorrecto (versión incorrecta del jar, etc ...) y reloading de clases (algunos jars se volvían a cargar, pero no a mockito, lo que conducía a la creación de instancias de una clase con el cargador de clase incorrecto).

@Aces Podría dar más detalles, como la versión y el nombre de la herramienta que está utilizando (maven, características, segura, Play Marco, JRebel quizá, etc ...)

+0

Reemplacé los simulacros con las implementaciones ArrayList y HashMap, y también probé el truco mediante upcasting como se sugiere en la respuesta. Ambas soluciones funcionaron bien. Así que no creo que haya ningún problema de classpath en el proyecto. He podido ejecutar casos de prueba con burlas hasta ahora. –

0

Lamentablemente, esto no es posibles

caso: ensayos sobre la API: razón

interface ConfigurationBuilder {...} 
configurationBuilder.newServerAction("s1").withName("111")....create(); 

principal de este uso es el mantenimiento de compatibilidad en tiempo de compilación. Pero Mockito no puede apoyar los genéricos en cadenas con RETURNS_MOCKS y opciones RETURNS_DEEP_STUBS debidos al tipo de borrado en Java:

Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1"); 
b.withName("111")...create(); 

resultado del ejemplo anterior debería ser serveraction pero en Mockito que es objeto de la clase generada.

ver Issue: Can not Return deep stubs from generic method that returns generic type #484