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
o IllegalStateException
. 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() {
AxisRange range = new AxisRange(0,100);
Runnable act = () -> range.setLowerBound(200);
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:
List myList = new ArrayList();
catchException(myList).get(1);
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 {
Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
URL url = DLLTestFixture.class.getResource("USERDLL.dll");
String path = url.toURI().getPath();
path = path.substring(0, path.lastIndexOf("/"));
NativeLibrary.addSearchPath("USERDLL", path);
Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);
assertThat(dll).isNotNull();
}