¿Cómo se afirma que una cierta excepción se lanza en las pruebas de JUnit 4?


¿Cómo puedo usar JUnit4 idiomáticamente para probar que algún código arroja una excepción?

Aunque ciertamente puedo hacer algo como esto:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

Recuerdo que hay una anotación o una Aserción.xyz o algo que es mucho menos desacoplados y mucho más en el espíritu de JUnit para este tipo de situaciones.

Author: rgettman, 2008-10-01

30 answers

JUnit 4 tiene soporte para esto:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}

Referencia: https://junit.org/junit4/faq.html#atests_7

 1996
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 05:27:06

Editar Ahora que JUnit5 ha sido lanzado, la mejor opción sería usar Assertions.assertThrows() (ver mi otra respuesta).

Si no ha migrado a JUnit 5, pero puede usar JUnit 4.7, puede usar el ExpectedException Regla:

public class FooTest {
  @Rule
  public final ExpectedException exception = ExpectedException.none();

  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    exception.expect(IndexOutOfBoundsException.class);
    foo.doStuff();
  }
}

Esto es mucho mejor que @Test(expected=IndexOutOfBoundsException.class) porque la prueba fallará si IndexOutOfBoundsException se lanza antes de foo.doStuff()

Ver este artículo para más detalles

 1183
Author: NamshubWriter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-01 16:43:56

Tenga cuidado al usar la excepción esperada, porque solo afirma que el método lanzó esa excepción, no una línea de código en particular en la prueba.

Tiendo a usar esto para probar la validación de parámetros, porque tales métodos suelen ser muy simples, pero las pruebas más complejas podrían servirse mejor con:

try {
    methodThatShouldThrow();
    fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}

Aplicar sentencia.

 417
Author: daveb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 09:36:52

Como se respondió antes, hay muchas maneras de lidiar con las excepciones en JUnit. Pero con Java 8 hay otra: usar expresiones Lambda. Con expresiones Lambda podemos lograr una sintaxis como esta:

@Test
public void verifiesTypeAndMessage() {
    assertThrown(new DummyService()::someMethod)
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Runtime exception occurred")
            .hasMessageStartingWith("Runtime")
            .hasMessageEndingWith("occurred")
            .hasMessageContaining("exception")
            .hasNoCause();
}

AssertThrown acepta una interfaz funcional, cuyas instancias se pueden crear con expresiones lambda, referencias de métodos o referencias de constructores. assertThrown acepta que la interfaz esperará y estará lista para manejar una excepción.

Esto es relativamente simple pero una técnica poderosa.

Echa un vistazo a esta entrada del blog que describe esta técnica: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

El código fuente se puede encontrar aquí: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

Divulgación: Soy el autor del blog y del proyecto.

 190
Author: Rafal Borowiec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-27 15:07:00

En junit, hay cuatro formas de probar la excepción.

  • Para junit4.x, utilice el atributo opcional "esperado" de la anotación de prueba

    @Test(expected = IndexOutOfBoundsException.class)
    public void testFooThrowsIndexOutOfBoundsException() {
        foo.doStuff();
    }
    
  • Para junit4.x, utilice la regla ExpectedException

    public class XxxTest {
        @Rule
        public ExpectedException thrown = ExpectedException.none();
    
        @Test
        public void testFooThrowsIndexOutOfBoundsException() {
            thrown.expect(IndexOutOfBoundsException.class)
            //you can test the exception message like
            thrown.expectMessage("expected messages");
            foo.doStuff();
        }
    }
    
  • También puede usar la clásica manera de probar / atrapar ampliamente utilizada en junit 3 framework

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            fail("expected exception was not occured.");
        } catch(IndexOutOfBoundsException e) {
            //if execution reaches here, 
            //it indicates this exception was occured.
            //so we need not handle it.
        }
    }
    
  • Finalmente, para junit5.x, también puede usar assertThrows de la siguiente manera

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());
        assertEquals("expected messages", exception.getMessage());
    }
    
  • So

    • el 1er camino es se usa cuando solo se desea probar el tipo de excepción
    • las otras tres formas se utilizan cuando desea probar el mensaje de excepción más
    • si usa junit 3, entonces se prefiere el 3er
    • si te gusta junit 5, entonces debería gustarte el 4th one
  • Para más información, puede leer este documento y la guía del usuario de junit5 para más detalles.

 87
Author: walsh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-08 13:53:58

Tl; dr

  • Pre-JDK8: Recomendaré el viejo bien try-catch bloquear.

  • Post-JDK8: Use AssertJ o lambdas personalizadas para afirmar un comportamiento excepcional.

Independientemente de Junit 4 o JUnit 5.

La larga historia

Es posible escribir usted mismo un hágalo usted mismo try-catch bloquear o usar las herramientas JUnit (@Test(expected = ...) o la regla JUnit @Rule ExpectedException función).

Pero estas formas no son tan elegantes y no se mezclan bien en cuanto a legibilidad con otras herramientas.

  1. Las try-catch bloque tienes que escribir el bloque alrededor del comportamiento probado, y escribir la afirmación en el bloque catch, que puede estar bien, pero muchos encuentran que este estilo interrumpe el flujo de lectura de una prueba. También necesita escribir un Assert.fail al final del bloque try de lo contrario la prueba puede perder un lado de las aserciones; PMD , findbugs o Sonar va a detectar problemas.

  2. La característica @Test(expected = ...) es interesante ya que puede escribir menos código y luego escribir esta prueba es supuestamente menos propenso a errores de codificación. Pero este enfoque carece de algunas áreas.

    • Si la prueba necesita verificar cosas adicionales en la excepción como la causa o el mensaje (los buenos mensajes de excepción son realmente importantes, tener un tipo de excepción preciso puede no ser suficiente).
    • También como la expectativa se coloca alrededor en el método, dependiendo de cómo se escribe el código probado, entonces la parte incorrecta del código de prueba puede lanzar la excepción, lo que lleva a una prueba positiva falsa y no estoy seguro de que PMD, findbugs o Sonar darán pistas sobre dicho código.

      @Test(expected = WantedException.class)
      public void call2_should_throw_a_WantedException__not_call1() {
          // init tested
          tested.call1(); // may throw a WantedException
      
          // call to be actually tested
          tested.call2(); // the call that is supposed to raise an exception
      }
      
  3. La regla ExpectedException también es un intento de corregir las advertencias anteriores, pero se siente un poco incómodo de usar, ya que utiliza una expectativa style, Los usuarios de EasyMock conocen muy bien este estilo. Podría ser conveniente para algunos, pero si sigues los principios Behaviour Driven Development (BDD) o Arrange Act Assert (AAA), la regla ExpectedException no encajará en esos estilos de escritura. Aparte de eso, puede sufrir el mismo problema que el camino @Test, dependiendo de dónde coloques la expectativa.

    @Rule ExpectedException thrown = ExpectedException.none()
    
    @Test
    public void call2_should_throw_a_WantedException__not_call1() {
        // expectations
        thrown.expect(WantedException.class);
        thrown.expectMessage("boom");
    
        // init tested
        tested.call1(); // may throw a WantedException
    
        // call to be actually tested
        tested.call2(); // the call that is supposed to raise an exception
    }
    

    Incluso la excepción esperada se coloca antes de la instrucción de prueba, rompe su flujo de lectura si el las pruebas siguen BDD o AAA.

    Ver también este comentario número sobre JUnit del autor de ExpectedException.

Así que estas opciones anteriores tienen toda su carga de advertencias, y claramente no son inmunes a los errores de codificador.

  1. Hay un proyecto que me di cuenta después de crear esta respuesta que parece prometedor, es excepción de captura.

    Como dice la descripción del proyecto, permite que un codificador escriba una línea de código fluida captura de la excepción y ofrecer esta excepción para la afirmación posterior. Y puedes usar cualquier biblioteca de aserciones como Hamcrest o AssertJ .

    Un ejemplo rápido tomado de la página de inicio:

    // given: an empty list
    List myList = new ArrayList();
    
    // when: we try to get the first element of the list
    when(myList).get(1);
    
    // then: we expect an IndexOutOfBoundsException
    then(caughtException())
            .isInstanceOf(IndexOutOfBoundsException.class)
            .hasMessage("Index: 1, Size: 0") 
            .hasNoCause();
    

    Como puede ver, el código es realmente sencillo, se captura la excepción en una línea específica, la API then es un alias que usará API AssertJ (similar a usar assertThat(ex).hasNoCause()...). En algún momento el proyecto se basó en FEST-Assert el antepasado de AssertJ. EDITAR: Parece que el proyecto está preparando un soporte para Java 8 Lambdas.

    Actualmente esta biblioteca tiene dos deficiencias:

    • En el momento de escribir este artículo es digno de mención decir que esta biblioteca está basada en Mockito 1.x, ya que crea una simulación del objeto probado detrás de la escena. Como Mockito todavía no está actualizado esta biblioteca no puede funcionar con clases finales o métodos finales. E incluso si se basa en mockito 2 en la versión actual, esto requeriría declarar un mockmaker global (inline-mock-maker), algo que puede no ser lo que quieres, ya que este mockmaker tiene diferentes inconvenientes que el mockmaker regular.

    • Requiere otra dependencia de prueba.

    Estos problemas no se aplicarán una vez que la biblioteca soporte lambdas, sin embargo la funcionalidad será duplicada por AssertJ toolset.

    Teniendo todo en cuenta si no desea utilizar la herramienta de excepción de captura, recomendaré la vieja buena manera de las try-catch bloque, al menos hasta el JDK7. Y para los usuarios de JDK 8, es posible que prefiera usar AssertJ, ya que ofrece más que solo afirmar excepciones.

  2. Con el JDK8, las lambdas entran en la escena de prueba, y han demostrado ser una forma interesante de afirmar un comportamiento excepcional. AssertJ se ha actualizado para proporcionar una API fluida agradable para afirmar un comportamiento excepcional.

    Y una prueba de muestra con AssertJ :

    @Test
    public void test_exception_approach_1() {
        ...
        assertThatExceptionOfType(IOException.class)
                .isThrownBy(() -> someBadIOOperation())
                .withMessage("boom!"); 
    }
    
    @Test
    public void test_exception_approach_2() {
        ...
        assertThatThrownBy(() -> someBadIOOperation())
                .isInstanceOf(Exception.class)
                .hasMessageContaining("boom");
    }
    
    @Test
    public void test_exception_approach_3() {
        ...
        // when
        Throwable thrown = catchThrowable(() -> someBadIOOperation());
    
        // then
        assertThat(thrown).isInstanceOf(Exception.class)
                          .hasMessageContaining("boom");
    }
    
  3. Con a casi reescritura completa de JUnit 5, las aserciones han sido mejoradas un poco, pueden resultar interesantes como una forma lista para usar de afirmar correctamente la excepción. Pero realmente la API de aserción sigue siendo un poco pobre, no hay nada afuera assertThrows.

    @Test
    @DisplayName("throws EmptyStackException when peeked")
    void throwsExceptionWhenPeeked() {
        Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    
        Assertions.assertEquals("...", t.getMessage());
    }
    

    Como has notado, assertEquals todavía está regresando void, y como tal no permite encadenar aserciones como AssertJ.

    También si recuerdas el choque de nombres con Matcher o Assert, prepárate para enfrentar el mismo choque por Assertions.

Me gustaría concluir que hoy (2017-03-03) La facilidad de uso de AssertJ, la API detectable, el rápido ritmo de desarrollo y como una dependencia de prueba de facto es la mejor solución con JDK8, independientemente del marco de prueba (JUnit o no), los JDKs anteriores deberían confiar entry-catch bloquea incluso si se sienten torpes.

Esta respuesta ha sido copiada de otra pregunta que no tiene la misma visibilidad, soy el mismo autor.

 62
Author: Brice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 08:51:46

Qué tal esto: Captura una excepción muy general, asegúrate de que salga del bloque catch, luego afirma que la clase de la excepción es lo que esperas que sea. Esta afirmación fallará si a) la excepción es del tipo incorrecto (eg. si tienes un puntero nulo en su lugar) y b) la excepción nunca fue lanzada.

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

  try {
    foo.doStuff();
  } catch (Throwable ex) {
    e = ex;
  }

  assertTrue(e instanceof IndexOutOfBoundsException);
}
 32
Author: Johan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-13 00:22:07

Solución de estilo BDD : JUnit 4 + Excepción de Captura + AssertJ

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

    then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);

}

Código fuente

Dependencias

eu.codearte.catch-exception:catch-exception:1.3.3
 30
Author: MariuszS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-08 19:35:25

Usando una aserción AssertJ, que se puede usar junto con JUnit:

import static org.assertj.core.api.Assertions.*;

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  Foo foo = new Foo();

  assertThatThrownBy(() -> foo.doStuff())
        .isInstanceOf(IndexOutOfBoundsException.class);
}

Es mejor que @Test(expected=IndexOutOfBoundsException.class) porque garantiza la línea esperada en la prueba arrojó la excepción y le permite verificar más detalles sobre la excepción, como mensaje, más fácil:

assertThatThrownBy(() ->
       {
         throw new Exception("boom!");
       })
    .isInstanceOf(Exception.class)
    .hasMessageContaining("boom");

Instrucciones de Maven / Gradle aquí.

 30
Author: weston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-11 18:24:43

Ahora que JUnit 5 ha lanzado, la mejor opción es usar Assertions.assertThrows() (ver la Guía del Usuario Junit 5).

Aquí hay un ejemplo que verifica que se lanza una excepción, y usa Truth para hacer afirmaciones sobre el mensaje de excepción:

public class FooTest {
  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    IndexOutOfBoundsException e = assertThrows(
        IndexOutOfBoundsException.class, foo::doStuff);

    assertThat(e).hasMessageThat().contains("woops!");
  }
}

Las ventajas sobre los enfoques en las otras respuestas son:

  1. Integrado en JUnit
  2. Se obtiene un mensaje de excepción útil si el código en la lambda no lanza una excepción, y una stacktrace si lanza una excepción diferente
  3. Conciso
  4. Permite que sus pruebas sigan Arrange-Act-Assert
  5. Puede indicar con precisión qué código espera lanzar la excepción
  6. No es necesario enumerar la excepción esperada en la cláusula throws
  7. Puede usar el marco de aserciones de su elección para hacer aserciones sobre la excepción capturada

Se agregará un método similar a org.junit Assert en JUnit 4.13.

 30
Author: NamshubWriter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-01 17:17:00

Para resolver el mismo problema que hice configurar un pequeño proyecto: http://code.google.com/p/catch-exception /

Usando este pequeño ayudante escribirías

verifyException(foo, IndexOutOfBoundsException.class).doStuff();

Esto es menos detallado que la regla ExpectedException de JUnit 4.7. En comparación con la solución proporcionada por skaffman, puede especificar en qué línea de código espera la excepción. Espero que esto ayude.

 29
Author: rwitzel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-28 09:26:21

Actualización: JUnit5 tiene una mejora para probar excepciones: assertThrows.

El siguiente ejemplo es de: Guía del usuario de Junit 5

 @Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> 
    {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

Respuesta original usando JUnit 4.

Hay varias maneras de probar que una excepción es lanzada. También he discutido las siguientes opciones en mi post Cómo escribir grandes pruebas unitarias con JUnit

Establece el parámetro expected @Test(expected = FileNotFoundException.class).

@Test(expected = FileNotFoundException.class) 
public void testReadFile() { 
    myClass.readFile("test.txt");
}

Usando try catch

public void testReadFile() { 
    try {
        myClass.readFile("test.txt");
        fail("Expected a FileNotFoundException to be thrown");
    } catch (FileNotFoundException e) {
        assertThat(e.getMessage(), is("The file test.txt does not exist!"));
    }

}

Probando con la regla ExpectedException.

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testReadFile() throws FileNotFoundException {

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage(startsWith("The file test.txt"));
    myClass.readFile("test.txt");
}

Puedes leer más sobre las pruebas de excepciones en wiki de JUnit4 para las pruebas de excepciones y mal.robot-Esperando excepciones JUnit Rule .

 24
Author: Dilini Rajapaksha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-05 16:03:12

También puedes hacer esto:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}
 19
Author: John Mikic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-13 00:21:01

En mi humilde opinión, la mejor manera de comprobar las excepciones en JUnit es el patrón try/catch/fail/assert:

// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
    sut.doThing();
    fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
                         // otherwise you may catch an exception for a dependency unexpectedly
    // a strong assertion on the message, 
    // in case the exception comes from anywhere an unexpected line of code,
    // especially important if your checking IllegalArgumentExceptions
    assertEquals("the message I get", e.getMessage()); 
}

El assertTrue podría ser un poco fuerte para algunas personas, por lo que assertThat(e.getMessage(), containsString("the message"); podría ser preferible.

 12
Author: Alex Collins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-14 18:07:21

Solución de JUnit 5

@Test
void testFooThrowsIndexOutOfBoundsException() {    
  Throwable exception = expectThrows( IndexOutOfBoundsException.class, foo::doStuff );

  assertEquals( "some message", exception.getMessage() );
}

Más información sobre JUnit 5 en http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

 10
Author: Daniel Käfer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-24 15:00:31

Probé muchos de los métodos aquí, pero eran complicados o no cumplían mis requisitos. De hecho, uno puede escribir un método helper simplemente:

public class ExceptionAssertions {
    public static void assertException(BlastContainer blastContainer ) {
        boolean caughtException = false;
        try {
            blastContainer.test();
        } catch( Exception e ) {
            caughtException = true;
        }
        if( !caughtException ) {
            throw new AssertionFailedError("exception expected to be thrown, but was not");
        }
    }
    public static interface BlastContainer {
        public void test() throws Exception;
    }
}

Úsalo así:

assertException(new BlastContainer() {
    @Override
    public void test() throws Exception {
        doSomethingThatShouldExceptHere();
    }
});

Cero dependencias: no hay necesidad de mockito, no hay necesidad de powermock; y funciona bien con las clases finales.

 9
Author: Hugh Perkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-10 15:02:44

JUnit tiene soporte incorporado para esto, con un atributo "esperado"

 8
Author: Mark Bessey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 07:05:49

Solución Java 8

Si desea una solución que:

  • Utiliza Java 8 lambdas
  • Does not depend on any JUnit magic
  • Le permite verificar múltiples excepciones dentro de un único método de prueba
  • Comprueba si una excepción es lanzada por un conjunto específico de líneas dentro de su método de prueba en lugar de cualquier línea desconocida en todo el método de prueba
  • Produce el objeto de excepción real que se lanzó para que pueda examinar más a fondo it

Aquí hay una función de utilidad que escribí:

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

(tomado de mi blog)

Utilícelo como sigue:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}
 8
Author: Mike Nakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-11 16:38:50

En mi caso siempre obtengo RuntimeException de la base de datos, pero los mensajes difieren. Y la excepción necesita ser manejada respectivamente. Así es como lo probé:

@Test
public void testThrowsExceptionWhenWrongSku() {

    // Given
    String articleSimpleSku = "999-999";
    int amountOfTransactions = 1;
    Exception exception = null;

    // When
    try {
        createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
    } catch (RuntimeException e) {
        exception = e;
    }

    // Then
    shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}

private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
    assertNotNull(e);
    assertTrue(e.getMessage().contains(message));
}
 6
Author: Macchiatow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-02 09:03:57

En JUnit 4 o posterior puede probar las excepciones de la siguiente manera

@Rule
public ExpectedException exceptions = ExpectedException.none();


esto proporciona una gran cantidad de características que se pueden utilizar para mejorar nuestras pruebas JUnit.
Si ves el siguiente ejemplo, estoy probando 3 cosas en la excepción.

  1. El tipo de excepción lanzada
  2. El Mensaje de excepción
  3. la causa de La excepción


public class MyTest {

    @Rule
    public ExpectedException exceptions = ExpectedException.none();

    ClassUnderTest classUnderTest;

    @Before
    public void setUp() throws Exception {
        classUnderTest = new ClassUnderTest();
    }

    @Test
    public void testAppleisSweetAndRed() throws Exception {

        exceptions.expect(Exception.class);
        exceptions.expectMessage("this is the exception message");
        exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));

        classUnderTest.methodUnderTest("param1", "param2");
    }

}
 5
Author: Jobin Joseph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-08 05:48:19

Podemos usar una aserción fail después del método que debe devolver una excepción:

try{
   methodThatThrowMyException();
   Assert.fail("MyException is not thrown !");
} catch (final Exception exception) {
   // Verify if the thrown exception is instance of MyException, otherwise throws an assert failure
   assertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");
   // In case of verifying the error message
   MyException myException = (MyException) exception;
   assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());
}
 5
Author: Shessuky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-20 10:34:05

La respuesta más flexible y elegante para Junit 4 que encontré en el blog Mkyoung. Tiene la flexibilidad de try/catch usando la anotación @Rule. Me gustó este enfoque porque ya necesitaba leer atributos específicos de una excepción personalizada.

package com.mkyong;

import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;

public class Exception3Test {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testNameNotFoundException() throws NameNotFoundException {

        //test specific type of exception
        thrown.expect(NameNotFoundException.class);

        //test message
        thrown.expectMessage(is("Name is empty!"));

        //test detail
        thrown.expect(hasProperty("errCode"));  //make sure getters n setters are defined.
        thrown.expect(hasProperty("errCode", is(666)));

        CustomerService cust = new CustomerService();
        cust.findByName("");

    }

}
 5
Author: Dherik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-06 13:17:09

Además de lo que NamShubWriter ha dicho, asegúrese de que:

  • La instancia ExpectedException es pública (Pregunta conexa)
  • La ExpectedException no es instanciada en digamos, el método @Before. Este post explica claramente todas las complejidades de la orden de ejecución de JUnit.

Haz no haz esto:

@Rule    
public ExpectedException expectedException;

@Before
public void setup()
{
    expectedException = ExpectedException.none();
}

Finalmente, esta entrada de blog ilustra claramente cómo afirmar que un se lanza cierta excepción.

 4
Author: Bruce Wayne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:24

Simplemente haga un Matcher que pueda ser apagado y encendido, así:

public class ExceptionMatcher extends BaseMatcher<Throwable> {
    private boolean active = true;
    private Class<? extends Throwable> throwable;

    public ExceptionMatcher(Class<? extends Throwable> throwable) {
        this.throwable = throwable;
    }

    public void on() {
        this.active = true;
    }

    public void off() {
        this.active = false;
    }

    @Override
    public boolean matches(Object object) {
        return active && throwable.isAssignableFrom(object.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not the covered exception type");
    }
}

Para usarlo:

Añadir public ExpectedException exception = ExpectedException.none();, entonces:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();
 4
Author: Tor P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-02 02:28:41

Tome por ejemplo, desea escribir Junit para el fragmento de código mencionado a continuación

public int divideByZeroDemo(int a,int b){

    return a/b;
}

public void exceptionWithMessage(String [] arr){

    throw new ArrayIndexOutOfBoundsException("Array is out of bound");
}

El código anterior es para probar alguna excepción desconocida que pueda ocurrir y el siguiente es para afirmar alguna excepción con un mensaje personalizado.

 @Rule
public ExpectedException exception=ExpectedException.none();

private Demo demo;
@Before
public void setup(){

    demo=new Demo();
}
@Test(expected=ArithmeticException.class)
public void testIfItThrowsAnyException() {

    demo.divideByZeroDemo(5, 0);

}

@Test
public void testExceptionWithMessage(){


    exception.expectMessage("Array is out of bound");
    exception.expect(ArrayIndexOutOfBoundsException.class);
    demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
}
 1
Author: Shirsh Sinha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-29 07:34:18

Con Java 8 puede crear un método tomando un código para verificar y la excepción esperada como parámetros:

private void expectException(Runnable r, Class<?> clazz) { 
    try {
      r.run();
      fail("Expected: " + clazz.getSimpleName() + " but not thrown");
    } catch (Exception e) {
      if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
    }
  }

Y luego dentro de su prueba:

expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);

Beneficios:

  • no depender de ninguna biblioteca
  • control localizado-más preciso y permite tener múltiples aserciones como esta dentro de una prueba si es necesario
  • fácil de usar
 0
Author: fahrenx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-01 12:03:38

Mi solución usando Java 8 lambdas:

public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable {
    try {
        action.run();
        Assert.fail("Did not throw expected " + expected.getSimpleName());
        return null; // never actually
    } catch (Throwable actual) {
        if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)'
            System.err.println("Threw " + actual.getClass().getSimpleName() 
                               + ", which is not a subtype of expected " 
                               + expected.getSimpleName());
            throw actual; // throw the unexpected Throwable for maximum transparency
        } else {
            return (T) actual; // return the expected Throwable for further examination
        }
    }
}

Tienes que definir una interfaz funcional, porque Runnable no declara el throws requerido.

@FunctionalInterface
public interface ThrowingRunnable {
    void run() throws Throwable;
}

El método se puede utilizar de la siguiente manera:

class CustomException extends Exception {
    public final String message;
    public CustomException(final String message) { this.message = message;}
}
CustomException e = assertThrows(CustomException.class, () -> {
    throw new CustomException("Lorem Ipsum");
});
assertEquals("Lorem Ipsum", e.message);
 0
Author: heio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-04 12:03:26

Hay dos formas de escribir el caso de prueba

  1. Anote la prueba con la excepción que arroja el método. Algo como esto @Test(expected = IndexOutOfBoundsException.class)
  2. Simplemente puede capturar la excepción en la clase de prueba usando el bloque try catch y afirmar en el mensaje que se lanza desde el método en la clase de prueba.

    try{
    }
    catch(exception to be thrown from method e)
    {
         assertEquals("message", e.getmessage());
    }
    

Espero que esto responda a su pregunta Feliz aprendizaje...

 0
Author: Mohit ladia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-09 07:23:04

La solución Junit4 con Java8 es usar esta función:

public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
    try {
        funky.call();
    } catch (Throwable e) {
        if (expectedException.isInstance(e)) {
            return e;
        }
        throw new AssertionError(
                String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
    }
    throw new AssertionError(
            String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}

El uso es entonces:

    assertThrows(ValidationException.class,
            () -> finalObject.checkSomething(null));

Tenga en cuenta que la única limitación es usar una referencia de objeto final en la expresión lambda. Esta solución permite continuar las aserciones de prueba en lugar de esperar thowable a nivel de método utilizando @Test(expected = IndexOutOfBoundsException.class) solución.

 0
Author: Donatello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-06 16:32:25

Recomiendo la biblioteca assertj-core para manejar la excepción en junit test

En java 8, así:

//given

//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));

//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);
 0
Author: Piotr R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-18 11:32:37