java - intellij - Mockito isA(Clase<T> clazz) ¿Cómo resolver el tipo de seguridad?
mockito-all (4)
En mi prueba tengo la siguiente línea:
when(client.runTask(anyString(), anyString(), isA(Iterable.class)).thenReturn(...)
isA(Iterable.class)
produce una advertencia de que necesita una conversión sin isA(Iterable.class)
para cumplir con el Iterable<Integer>
. ¿Qué es la sintaxis para eso?
isA(Iterable<Integer>.class)
isA((Iterable<Integer>)Iterable.class
No funcionan.
¿Alguna sugerencia?
Mockito / Hamcrest y clases genéricas.
Sí, este es un problema general con Mockito / Hamcrest. Generalmente el uso de isA()
con clases genéricas produce una advertencia.
Existen emparejadores de Mockito predeterminados para las clases genéricas más comunes: anyList() , anyMap()
, anySet()
y anyCollection()
.
Sugerencias:
anyIterable () en Mockito 2.1.0
Mockito 2.1.0 agregó un nuevo método anyIterable() para hacer coincidir Iterables:
when(client.runTask(anyString(), anyString(), anyIterable()).thenReturn(...)
Ignorar en Eclipse
Si solo quieres deshacerte de la advertencia en Eclipse. La opción existe desde Eclipse Indigo :
Ventana> Preferencias> Java> Compilador> Errores / Advertencias> Tipos genéricos> Ignorar problemas de tipo genérico inevitables
Solución rápida con @SuppressWarnings
Le sugiero que haga esto si tiene el problema una sola vez. Personalmente no recuerdo haber necesitado nunca un isA(Iterable.class)
.
Como dice Daniel Pryden, puede limitar @SuppressWarnings
a una variable local o un método auxiliar.
Utilice un genérico isA () matcher con TypeToken
Esto resuelve el problema para siempre. Pero tiene dos desventajas:
- La sintaxis no es demasiado bonita y puede confundir a algunas personas.
- Tiene una dependencia adicional de la biblioteca que proporciona la clase
TypeToken
. Aquí utilicé la clase TypeToken de guava . También hay una claseTypeToken
en Gson y unGenericType
en JAX-RS.
Usando el matcher genérico:
import static com.arendvr.matchers.InstanceOfGeneric.isA;
import static org.mockito.ArgumentMatchers.argThat;
// ...
when(client.runTask(anyString(), anyString(), argThat(isA(new TypeToken<Iterable<Integer>>() {}))))
.thenReturn(...);
Clasificadora genérica:
package com.arendvr.matchers;
import com.google.common.reflect.TypeToken;
import org.mockito.ArgumentMatcher;
public class InstanceOfGeneric<T> implements ArgumentMatcher<T> {
private final TypeToken<T> typeToken;
private InstanceOfGeneric(TypeToken<T> typeToken) {
this.typeToken = typeToken;
}
public static <T> InstanceOfGeneric<T> isA(TypeToken<T> typeToken) {
return new InstanceOfGeneric<>(typeToken);
}
@Override
public boolean matches(Object item) {
return item != null && typeToken.getRawType().isAssignableFrom(item.getClass());
}
}
Esto es lo que hago:
// Cast from Class<Iterable> to Class<Iterable<Integer>> via the raw type.
// This is provably safe due to erasure, but will generate an unchecked warning
// nonetheless, which we suppress.
@SuppressWarnings("unchecked")
Class<Iterable<Integer>> klass
= (Class<Iterable<Integer>>) (Class) Iterable.class;
// later
isA(klass) // <- now this is typesafe
No hay manera de hacer esto. Para simplificar, no puede inicializar esta variable sin previo aviso:
Class<Iterable<Integer>> iterableIntegerClass = ?
Una solución podría ser usar el IntegerIterable
pseudo-typedef , usted crea y usa una interfaz IntegerIterable
interface IntegerIterable extends Iterable<Integer> {}
entonces
isA(IntegerIterable.class)
no producirá más advertencia. Pero tendrá que extender la clase implementando Iterable
para permitir que implementen IntegerIterable
:) Por ejemplo:
public class IntegerArrayList extends ArrayList<Integer> implements IntegerIterable {}
Mmm sabroso ...
Por lo tanto, le sugeriré que considere simplemente empapelar las grietas agregando a su método:
@SuppressWarnings("unchecked")
Puede agregar @SuppressWarnings("unchecked")
sobre la declaración. No hay otra forma, pero si te molesta, puedes mover el modelo a un método auxiliar.