Afirmar sobre una lista en Junit

¿Cómo hacer afirmaciones sobre una lista en un caso de prueba JUnit ? No solo el tamaño de la lista, sino también el contenido de la lista.

Me di cuenta de que esto fue preguntado hace un par de años, probablemente esta característica no existía entonces. Pero ahora, es fácil simplemente hacer esto:

 @Test public void test_array_pass() { List actual = Arrays.asList("fee", "fi", "foe"); List expected = Arrays.asList("fee", "fi", "foe"); assertThat(actual, is(expected)); assertThat(actual, is(not(expected))); } 

Si tiene instalada una versión reciente de Junit con Hamcrest, simplemente agregue estas importaciones:

 import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; 

http://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat(T, org.hamcrest.Matcher)

http://junit.org/junit4/javadoc/latest/org/hamcrest/CoreMatchers.html

http://junit.org/junit4/javadoc/latest/org/hamcrest/core/Is.html

Esta es una respuesta heredada, adecuada para JUnit 4.3 y siguientes. La versión moderna de JUnit incluye un mensaje de error legible incorporado en el método assertThat. Prefiere otras respuestas sobre esta pregunta, si es posible.

 List a = resultFromTest(); List expected = Arrays.asList(new E(), new E(), ...); assertTrue("Expected 'a' and 'expected' to be equal."+ "\n 'a' = "+a+ "\n 'expected' = "+expected, expected.equals(a)); 

Para el registro, como @Paul mencionó en su comentario a esta respuesta, dos List s son iguales:

si y solo si el objeto especificado también es una lista, ambas listas tienen el mismo tamaño, y todos los pares correspondientes de elementos en las dos listas son iguales. (Dos elementos e1 y e2 son iguales si (e1==null ? e2==null : e1.equals(e2)) .) En otras palabras, dos listas se definen como iguales si contienen los mismos elementos en el mismo orden . Esta definición asegura que el método equals funciona correctamente en diferentes implementaciones de la interfaz de la List .

Vea los JavaDocs de la interfaz de la List .

No se transforme en una cadena y compare. Esto no es bueno para el rendimiento. En el junit, dentro de Corematchers, hay una coincidencia para this => hasItems

 List yourList = Arrays.asList(1,2,3,4) assertThat(yourList, CoreMatchers.hasItems(1,2,3,4,5)); 

Esta es la mejor manera que conozco para verificar elementos en una lista.

Si no le importa el orden de los elementos, recomiendo ListAssert.assertEquals en junit-addons.

Enlace: http://junit-addons.sourceforge.net/

Para los usuarios perezosos de Maven:

   junit-addons junit-addons 1.4 test  
 List figureTypes = new ArrayList( Arrays.asList( 1, 2 )); List figureTypes2 = new ArrayList( Arrays.asList( 1, 2)); assertTrue(figureTypes .equals(figureTypes2 )); 

si no desea crear una lista de matriz, puede intentar esto también

 @Test public void test_array_pass() { List list = Arrays.asList("fee", "fi", "foe"); Strint listToString = list.toString(); Assert.assertTrue(listToString.contains("[fee, fi, foe]")); // passes } 

¡No reinventes la rueda!

Hay una biblioteca de Google Code que hace esto por usted: Hamcrest

[Hamcrest] Proporciona una biblioteca de objetos de coincidencia (también conocidos como restricciones o predicados) que permite que las reglas de “coincidencia” se definan declarativamente, para ser utilizadas en otros marcos. Los escenarios típicos incluyen marcos de prueba, bibliotecas burlonas y reglas de validación UI.

Puede usar assertEquals en junit.

 import org.junit.Assert; import org.junit.Test; @Test public void test_array_pass() { List actual = Arrays.asList("fee", "fi", "foe"); List expected = Arrays.asList("fee", "fi", "foe"); Assert.assertEquals(actual,expected); } 

Si el orden de los elementos es diferente, devolverá el error.

Si está afirmando una lista de objetos modelo, debe anular el método equals en el modelo específico.

  @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj instanceof ModelName) { ModelName other = (ModelName) obj; return this.getItem().equals(other.getItem()) ; } return false; } 

No hago esto, todas las respuestas anteriores dan la solución exacta para comparar dos listas de Objetos. La mayoría de los enfoques anteriores pueden ser útiles para seguir únicamente el límite de comparaciones: comparación de tamaños: comparación de referencias

Pero si tenemos listas del mismo tamaño de objetos y diferentes datos en el nivel de objetos, entonces estos enfoques de comparación no ayudarán.

Creo que el siguiente enfoque funcionará perfectamente con la anulación de iguales y el método hashcode en el objeto definido por el usuario.

Utilicé Xstream lib para anular equals y hashcode pero también podemos anular equals y hashcode por out logics / comparison.

Aquí está el ejemplo para su referencia

  import com.thoughtworks.xstream.XStream; import java.text.ParseException; import java.util.ArrayList; import java.util.List; class TestClass { private String name; private String id; public void setName(String value) { this.name = value; } public String getName() { return this.name; } public String getId() { return id; } public void setId(String id) { this.id = id; } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object o) { XStream xstream = new XStream(); String oxml = xstream.toXML(o); String myxml = xstream.toXML(this); return myxml.equals(oxml); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { XStream xstream = new XStream(); String myxml = xstream.toXML(this); return myxml.hashCode(); } } public class XstreamCompareTest { public static void main(String[] args) throws ParseException { checkObjectEquals(); } private static void checkObjectEquals() { List testList1 = new ArrayList(); TestClass tObj1 = new TestClass(); tObj1.setId("test3"); tObj1.setName("testname3"); testList1.add(tObj1); TestClass tObj2 = new TestClass(); tObj2.setId("test2"); tObj2.setName("testname2"); testList1.add(tObj2); testList1.sort((TestClass t1, TestClass t2) -> t1.getId().compareTo(t2.getId())); List testList2 = new ArrayList(); TestClass tObj3 = new TestClass(); tObj3.setId("test3"); tObj3.setName("testname3"); testList2.add(tObj3); TestClass tObj4 = new TestClass(); tObj4.setId("test2"); tObj4.setName("testname2"); testList2.add(tObj4); testList2.sort((TestClass t1, TestClass t2) -> t1.getId().compareTo(t2.getId())); if (isNotMatch(testList1, testList2)) { System.out.println("The list are not matched"); } else { System.out.println("The list are matched"); } } private static boolean isNotMatch(List clist1, List clist2) { return clist1.size() != clist2.size() || !clist1.equals(clist2); } } 

Lo más importante es que puede ignorar los campos por Anotación (@XStreamOmitField) si no desea incluir ningún campo en la verificación igual de Objetos. Hay muchas Anotaciones como esta para configurar, así que echa un vistazo profundo a las anotaciones de esta lib.

Estoy seguro de que esta respuesta le ahorrará tiempo para identificar el enfoque correcto para comparar dos listas de objetos :). Comente si ve algún problema al respecto.

assertEquals(Object, Object) de JUnit4 / JUnit 5 o assertThat(actual, is(expected)); de Hamcrest propuesto en las otras respuestas solo funcionará cuando ambos equals() y toString() son anulados para las clases (y profundamente) de los objetos comparados.

Importa porque la prueba de igualdad en la afirmación se basa en equals() y el mensaje de falla de prueba se basa en toString() de los objetos comparados.
Para clases integradas como String , Integer y así sucesivamente … no hay problema, ya que anulan tanto equals() como toString() . Por lo tanto, es perfectamente válido afirmar List o List con assertEquals(Object,Object) .
Y sobre este asunto: debe anular equals() en una clase porque tiene sentido en términos de igualdad de objetos, no solo para hacer las aserciones más fáciles en una prueba con JUnit.
Para hacer las aserciones más fáciles, tiene otras formas.
Como una buena práctica, estoy a favor de las bibliotecas assertion / matcher.

Aquí hay una solución AssertJ .

org.assertj.core.api.ListAssert.containsExactly() es lo que necesita: verifica que el grupo real contenga exactamente los valores dados y nada más, en el orden establecido en el javadoc.

Supongamos una clase Foo donde agrega elementos y dónde puede obtener eso.
Una prueba unitaria de Foo que afirma que las dos listas tienen el mismo contenido podría verse así:

 import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @Test void add() throws Exception { Foo foo = new Foo(); foo.add("One", "Two", "Three"); Assertions.assertThat(foo.getElements()) .containsExactly("One", "Two", "Three"); } 

Un buen punto de AssertJ es que declarar una List como se espera no es necesario: hace que la afirmación sea más recta y el código más legible:

 Assertions.assertThat(foo.getElements()) .containsExactly("One", "Two", "Three"); 

Pero las bibliotecas Assertion / matcher son imprescindibles porque estas realmente van más allá.
Supongamos ahora que Foo no almacena las instancias de String , sino de Bar .
Esa es una necesidad muy común. Con AssertJ, la afirmación es aún simple de escribir. Mejor puedes afirmar que el contenido de la lista es igual incluso si la clase de los elementos no anula equals()/hashCode() mientras que el modo JUnit requiere que:

 import org.assertj.core.api.Assertions; import static org.assertj.core.groups.Tuple.tuple; import org.junit.jupiter.api.Test; @Test void add() throws Exception { Foo foo = new Foo(); foo.add(new Bar(1, "One"), new Bar(2, "Two"), new Bar(3, "Three")); Assertions.assertThat(foo.getElements()) .extracting(Bar::getId, Bar::getName) .containsExactly(tuple(1, "One"), tuple(2, "Two"), tuple(3, "Three")); }