2010-03-24 6 views
38

Me gustaría utilizar hamcrest para afirmar que dos mapas son iguales, es decir, tienen el mismo conjunto de teclas apuntando a los mismos valores.Igualdad de mapas con Hamcrest

Mi actual mejor estimación es:

assertThat(affA.entrySet(), hasItems(affB.entrySet()); 

lo que da:

El assertThat método (T, Matcher) en el tipo de aserción no es aplicable a los argumentos (Set>, Matcher> >>)

También he estudiado las variaciones de containsAll y algunas otras proporcionadas por los paquetes de hamcrest. ¿Alguien puede señalarme en la dirección correcta? ¿O tengo que escribir un marcador personalizado?

+0

También he intentado 'containsAll' et al. Hace algún tiempo y no parecía funcionar - al parecer, Hamcrest es un poco poco confiable todavía :-( –

+7

¿Hay alguna razón por la cual no puedas usar los '.equals()' de la implementación del Mapa? –

+3

Ah, yo no No se dio cuenta de que las colecciones hacen comparaciones apropiadas de .equals(). ¿Siempre ha sido así? Eso hace la vida mucho más fácil. ¡Gracias! –

Respuesta

41

El camino más corto que he llegado con dos afirmaciones es:

assertThat(affA.entrySet(), everyItem(isIn(affB.entrySet()))); 
assertThat(affB.entrySet(), everyItem(isIn(affA.entrySet()))); 

Pero también es probable que pueda hacer:

assertThat(affA.entrySet(), equalTo(affB.entrySet())); 

dependiendo de las implementaciones de los mapas.

ACTUALIZACIÓN: en realidad hay una declaración que funciona independientemente de los tipos de colección:

assertThat(affA.entrySet, both(everyItem(isIn(affB.entrySet()))).and(containsInAnyOrder(affB.entrySet()))); 
+0

¿Qué pasa con .equals()? – Taras

+3

@Taras: el informe es menos útil con' .equals() ' –

33

A veces Map.equals() es suficiente. Pero a veces usted no sabe que el tipo de Map s es devuelto por el código bajo prueba, por lo que no sabe si .equals() comparará correctamente ese mapa de tipo desconocido devuelto por el código con el mapa creado por usted. O no desea vincular su código con tales pruebas.

Además, la construcción de un mapa separado para comparar el resultado con el que es mi humilde opinión no muy elegante:

Map<MyKey, MyValue> actual = methodUnderTest(); 

Map<MyKey, MyValue> expected = new HashMap<MyKey, MyValue>(); 
expected.put(new MyKey(1), new MyValue(10)); 
expected.put(new MyKey(2), new MyValue(20)); 
expected.put(new MyKey(3), new MyValue(30)); 
assertThat(actual, equalTo(expected)); 

Yo prefiero usar machers:

import static org.hamcrest.Matchers.hasEntry; 

Map<MyKey, MyValue> actual = methodUnderTest(); 
assertThat(actual, allOf(
         hasSize(3), // make sure there are no extra key/value pairs in map 
         hasEntry(new MyKey(1), new MyValue(10)), 
         hasEntry(new MyKey(2), new MyValue(20)), 
         hasEntry(new MyKey(3), new MyValue(30)) 
)); 

tengo que definir hasSize() a mí mismo:

public static <K, V> Matcher<Map<K, V>> hasSize(final int size) { 
    return new TypeSafeMatcher<Map<K, V>>() { 
     @Override 
     public boolean matchesSafely(Map<K, V> kvMap) { 
      return kvMap.size() == size; 
     } 

     @Override 
     public void describeTo(Description description) { 
      description.appendText(" has ").appendValue(size).appendText(" key/value pairs"); 
     } 
    }; 
} 

Y hay otra variante de hasEntry() que toma matchers como parámetros en lugar de valores exactos de clave y valor. Esto puede ser útil en caso de que necesite algo más que la prueba de igualdad de cada clave y valor.

+2

En lugar de usar su propio método 'hasSize', debe usar, 'org.hamcrest.collection .IsMapWithSize.aMapWithSize (Matcher ) ' – Eric

2

Estoy a favor de usar Guava ImmutableMap. Admiten Map.equals() y son fáciles de construir. El único truco es especificar explícitamente los parámetros de tipo, ya que hamcrest asumirá el tipo ImmutableMap.

assertThat(actualValue, 
      Matchers.<Map<String, String>>equalTo(ImmutableMap.of(
       "key1", "value", 
       "key2", "other-value" 
))); 
2

Otra opción disponible ahora es usar el Cirneco extension para Hamcrest. Tiene hasSameKeySet() (así como otros emparejadores para "colecciones" de Guava). De acuerdo con el ejemplo, será:

assertThat(affA, hasSameKeySet(affB)); 

Usted puede utilizar el siguiente dependencia para un proyecto basado en JDK7:

<dependency> 
    <groupId>it.ozimov</groupId> 
    <artifactId>java7-hamcrest-matchers</artifactId> 
    <version>0.7.0</version> 
</dependency> 

o el siguiente si está utilizando JDK8 o superiores:

<dependency> 
    <groupId>it.ozimov</groupId> 
    <artifactId>java8-hamcrest-matchers</artifactId> 
    <version>0.7.0</version> 
</dependency> 
+0

¿No sería eso simplemente comparar las claves pero no los valores? La pregunta quería comparar valores también. –

+0

@ Dr.Hans-PeterStörr No, la pregunta muestra que los conjuntos de entradas se comparan – JeanValjean

0

Hamcrest ahora tiene Matcher para la colección de tallas.

org.hamcrest.collection.IsCollectionWithSize

+2

Eso no responde a la pregunta original. – Guenther

0

Esto funciona como un encanto y no requiere dos afirmaciones como la respuesta aceptada.

assertThat(actualData.entrySet().toArray(), 
    arrayContainingInAnyOrder(expectedData.entrySet().toArray())); 
0

Si es necesario comparar un conjunto de resultados con las expectativas y si usted elige utilizar assertj biblioteca, puede hacer esto:

// put set of expected values by your test keys 
Map<K, V> expectations = ...; 

// for each test key get result 
Map<K, V> results = expectations.keySet().stream().collect(toMap(k -> k, k -> getYourProductionResult(k))); 

assertThat(results).containsAllEntriesOf(expectations); 

Tenga en cuenta que no se puede comparar containsAllEntriesOf mapas por la igualdad. Si su código de producción devuelve realmente un Map<K, V>, es posible que desee agregar un cheque para las claves assertThat(results).containsOnlyKeys((K[]) expectations.keySet().toArray());