Hay un fail()
método en la biblioteca JUnit4. Me gusta, pero experimento una falta de pass()
método que no está presente en la biblioteca. ¿Por que es esto entonces?
Descubrí que puedo usarlo assertTrue(true)
en su lugar, pero aún parece poco lógico.
@Test
public void testSetterForeignWord(){
try {
card.setForeignWord("");
fail();
} catch (IncorrectArgumentForSetter ex){
}
// assertTrue(true);
}
pass
método.Respuestas:
Siempre que la prueba no arroje una excepción, pasa, a menos que su
@Test
anotación especifique una excepción esperada. Supongo quepass()
podría lanzar una excepción especial que JUnit siempre interpreta como aprobada, para cortocircuitar la prueba, pero eso iría en contra del diseño habitual de las pruebas (es decir, asumir el éxito y solo fallar si falla una afirmación) y, si la gente obtiene la idea de que era preferible usarlopass()
, ralentizaría significativamente un gran conjunto de pruebas aprobadas (debido a la sobrecarga de creación de excepciones). Reprobar las pruebas no debería ser la norma, por lo que no es gran cosa si tienen esa sobrecarga.Tenga en cuenta que su ejemplo podría reescribirse así:
@Test(expected=IncorrectArgumentForSetter.class) public void testSetterForeignWord("") throws Exception { card.setForeignWord(""); }
Además, debería favorecer el uso de excepciones estándar de Java. Su
IncorrectArgumentForSetter
probablemente debería haber unaIllegalArgumentException
.fuente
pass()
método no puede simplemente no hacer nada, no sea que sea posible que una prueba falle después de llamarlo. Así que eliminé esa oración.Llame a la
return
declaración cada vez que su prueba haya terminado y aprobado.fuente
Creo que esta pregunta necesita una respuesta actualizada, ya que la mayoría de las respuestas aquí están bastante desactualizadas.
En primer lugar a la pregunta del OP:
Creo que está bastante bien aceptado que introducir el concepto de "superación esperada" en JUnit fue un mal movimiento, ya que esa excepción podría plantearse en cualquier lugar y pasará la prueba. Funciona si está lanzando (y afirmando) excepciones muy específicas de dominio, pero solo lanzo ese tipo de excepciones cuando estoy trabajando en un código que debe ser absolutamente impecable, la mayoría de APIS simplemente arrojará las excepciones integradas como
IllegalArgumentException
oIllegalStateException
. Si dos llamadas que hagas podrían arrojar potencialmente estas excepciones, entonces la@ExpectedException
anotación pondrá una barra verde en tu prueba, incluso si es la línea incorrecta la que arroja la excepción.Para esta situación, escribí una clase que estoy seguro de que muchos otros aquí han escrito, ese es un
assertThrows
método:public class Exceptions { private Exceptions(){} public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){ try{ actionThatShouldThrow.run(); fail("expected action to throw " + expectedException.getSimpleName() + " but it did not."); } catch(Exception e){ if ( ! expectedException.isInstance(e)) { throw e; } } } }
este método simplemente regresa si se lanza la excepción, lo que le permite hacer más afirmaciones / verificaciones en su prueba.
con la sintaxis de Java 8, su prueba se ve muy bien. A continuación se muestra una de las pruebas más simples en nuestro modelo que usa el método:
@Test public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() { //setup AxisRange range = new AxisRange(0,100); //act Runnable act = () -> range.setLowerBound(200); //assert assertThrows(IllegalArgumentException.class, act); }
estas pruebas son un poco inestables porque el paso "actuar" en realidad no realiza ninguna acción, pero creo que el significado sigue siendo bastante claro.
También hay una pequeña biblioteca en maven llamada catch-exception que usa la sintaxis de estilo mockito para verificar que se lanzan excepciones. Se ve bonito, pero no soy fanático de los proxies dinámicos. Dicho esto, la sintaxis es tan elegante que sigue siendo tentadora:
// given: an empty list List myList = new ArrayList(); // when: we try to get the first element of the list // then: catch the exception if any is thrown catchException(myList).get(1); // then: we expect an IndexOutOfBoundsException assert caughtException() instanceof IndexOutOfBoundsException;
Por último, para la situación con la que me encontré para llegar a este hilo, hay una manera de ignorar las pruebas si se cumple alguna condición.
En este momento estoy trabajando para que se llamen algunas DLL a través de una biblioteca de carga de biblioteca nativa de Java llamada JNA, pero nuestro servidor de compilación está en ubuntu. Me gusta intentar impulsar este tipo de desarrollo con las pruebas JUnit, aunque en este momento están lejos de ser "unidades". Lo que quiero hacer es ejecutar la prueba si estoy en una máquina local, pero ignorar la prueba si estamos en ubuntu. JUnit 4 tiene una provisión para esto, llamada
Assume
:@Test public void when_asking_JNA_to_load_a_dll() throws URISyntaxException { //this line will cause the test to be branded as "ignored" when "isCircleCI" //(the machine running ubuntu is running this test) is true. Assume.assumeFalse(BootstrappingUtilities.isCircleCI()); //an ignored test will typically result in some qualifier being put on the results, //but will also not typically prevent a green-ton most platforms. //setup URL url = DLLTestFixture.class.getResource("USERDLL.dll"); String path = url.toURI().getPath(); path = path.substring(0, path.lastIndexOf("/")); //act NativeLibrary.addSearchPath("USERDLL", path); Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class); //assert assertThat(dll).isNotNull(); }
fuente
También estaba buscando un
pass
método para JUnit, de modo que pudiera cortocircuitar algunas pruebas que no eran aplicables en algunos escenarios (hay pruebas de integración, en lugar de pruebas unitarias puras). Lástima que no esté allí.Afortunadamente, hay una manera de ignorar una prueba condicionalmente, que en realidad se ajusta aún mejor en mi caso usando el
assumeTrue
método:Entonces, aquí la prueba se ejecutará solo si isTestApplicable es verdadero; de lo contrario, se ignorará la prueba.
fuente
No es necesario el método de paso porque cuando no se lanza ninguna AssertionFailedException desde el código de prueba, el caso de prueba unitario pasará.
El método fail () en realidad arroja una AssertionFailedException para fallar el testCase si el control llega a ese punto.
fuente
Creo que esta pregunta es el resultado de un pequeño malentendido del proceso de ejecución de la prueba. En JUnit (y otras herramientas de prueba) los resultados se cuentan por método, no por llamada de aserción. No hay un contador, que realiza un seguimiento de cuántos aprobados / fallidos
assertX
se ejecutaron.JUnit ejecuta cada método de prueba por separado. Si el método devuelve correctamente, la prueba se registró como "aprobada". Si se produce una excepción, la prueba se registró como "fallida". En el último caso, son posibles dos subcasos: 1) una excepción de aserción JUnit, 2) cualquier otro tipo de excepciones. El estado será "fallido" en el primer caso y "error" en el segundo caso.
En la
Assert
clase se encuentran disponibles muchos métodos abreviados para lanzar excepciones de aserción. En otras palabras,Assert
es una capa de abstracción sobre las excepciones de JUnit.Por ejemplo, este es el código fuente de
assertEquals
en GitHub :/** * Asserts that two Strings are equal. */ static public void assertEquals(String message, String expected, String actual) { if (expected == null && actual == null) { return; } if (expected != null && expected.equals(actual)) { return; } String cleanMessage = message == null ? "" : message; throw new ComparisonFailure(cleanMessage, expected, actual); }
Como puede ver, en caso de igualdad no pasa nada, de lo contrario se lanzará una excepción.
Entonces:
assertEqual("Oh!", "Some string", "Another string!");
simplemente lanza una
ComparisonFailure
excepción, que será detectada por JUnit, yassertEqual("Oh?", "Same string", "Same string");
no hace nada.
En resumen, algo como
pass()
no tendría ningún sentido, porque no hizo nada.fuente