Hamcrest comparar colecciones

114

Estoy tratando de comparar 2 listas:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

Pero idea

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

¿Cómo debo escribirlo?

xander27
fuente

Respuestas:

161

Si quiere afirmar que las dos listas son idénticas, no complique las cosas con Hamcrest:

assertEquals(expectedList, actual.getList());

Si realmente tiene la intención de realizar una comparación insensible al orden, puede llamar al containsInAnyOrdermétodo varargs y proporcionar valores directamente:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(Suponiendo que su lista es de String, en lugar de Agent, para este ejemplo).

Si realmente desea llamar a ese mismo método con el contenido de un List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

Sin esto, está llamando al método con un solo argumento y creando un Matcherque espera coincidir con un Iterabledonde cada elemento es un List. No se puede utilizar para coincidir con un List.

Es decir, no puede hacer coincidir a List<Agent>con a Matcher<Iterable<List<Agent>>, que es lo que intenta su código.

Joe
fuente
+1 para "Si realmente desea llamar al mismo método con el contenido de una lista". Lamentablemente, no pude resolver eso por mí mismo. Especialmente que hay un constructor que toma una colección.
Eyad Ebrahim
3
@Tim No del todo; containsInAnyOrderrequiere que todos los elementos estén presentes, por lo que la primera afirmación fallará. Vea hasItemssi desea verificar que al menos esos elementos estén presentes.
Joe
4
Si usa containsInAnyOrder, primero debe asegurarse de que ambas listas tengan el mismo tamaño ... Si actual.getList()contiene "item1", "item3", "item2", la prueba pasará y tal vez desee asegurarse de que solo contenga los elementos enumerados ... En ese caso, podría usar assertThat(actual.getList().size(), equalTo(2));antes de containsInAnyOrder, de esta manera se asegura de que ambas listas tengan el mismo contenido.
Martin
1
@Martin estás pensando hasItems. El cheque adicional no es necesario aquí. Vea el comentario a Tim arriba, y también ¿En qué se diferencian hasItems, contains y containsInAnyOrder de Hamcrest?
Joe
1
Usuarios de Kotlin : ¡no olviden agregar el operador de propagación ( *expectedList.toTypedArray()) al pasar una matriz como varargs!
James Bowman
62
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Versión más corta de la respuesta de @ Joe sin parámetros redundantes.

Jofsey
fuente
28

Para complementar la respuesta de @ Joe:

Hamcrest le proporciona tres métodos principales para hacer coincidir una lista:

contains Comprueba la coincidencia de todos los elementos tomando en cuenta el orden, si la lista tiene más o menos elementos, fallará

containsInAnyOrder Comprueba que coincidan todos los elementos y no importa el orden, si la lista tiene más o menos elementos, fallará

hasItems Comprueba solo los objetos especificados, no importa si la lista tiene más

hasItem Comprueba solo un objeto, no importa si la lista tiene más

Todos ellos pueden recibir una lista de objetos y usar el equalsmétodo de comparación o se pueden mezclar con otros comparadores como @borjab mencionado:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains (E ...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html #containsInAnyOrder (java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems (T ...)

rvazquezglez
fuente
Un poco tarde para la fiesta, pero gracias por la descripción de las diferencias entre cada método.
Marcos de Andrade
Gran decisión en caso de que los elementos de la lista no sean de tipo primitivo.
Stanislav Tsepa
¿Existe alguna forma segura de hacer esto?
andresp
15

Con las bibliotecas de Hamcrest existentes (a partir de la versión 2.0.0.0), está obligado a usar el método Collection.toArray () en su colección para usar containsInAnyOrder Matcher. Mucho mejor sería agregar esto como un método separado a org.hamcrest.Matchers:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

En realidad, terminé agregando este método a mi biblioteca de prueba personalizada y lo usé para aumentar la legibilidad de mis casos de prueba (debido a la menor verbosidad).

yvolk
fuente
2
Bonito, usaré este ayudante. El mensaje de confirmación aquí es más informativo: nombra los elementos faltantes uno por uno, no solo: la lista debe ser elem1, elem2, .. elem99, pero obtuve elem1, elem2, ..., elem98 - buena suerte encontrar el que falta.
pihentagy
3

Asegúrese de que las Objects de su lista se hayan equals()definido. Luego

    assertThat(generatedList,is(equalTo(expectedList)));

trabajos.

Jim Jarrett
fuente
1

Para obtener una lista de objetos, es posible que necesite algo como esto:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

Use containsInAnyOrder si no desea verificar el orden de los objetos.

PD Cualquier ayuda para evitar la advertencia que se suprime será muy apreciada.

borjab
fuente
-3

Para comparar dos listas con el orden de uso conservado,

assertThat(actualList, contains("item1","item2"));
Shravan Ramamurthy
fuente
Esto no responde a la pregunta.
kamczak
Lo hace parcialmente.
rvazquezglez
@rvazquezglez ¿Qué quieres decir? ¿Por qué dices eso? El resultado del método está bien en mi entorno.
niaomingjian
@niaomingjian El código está verificando que actualListcontiene los elementos dentro del containsmatcher, que fallará si los elementos no están en el mismo orden y fallará también si contiene más elementos o falta uno.
rvazquezglez
@rvazquezglez, entonces el propósito del código es examinar la igualdad exacta (mismas longitudes, valores y orden) en dos listas, ¿verdad?
niaomingjian