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

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

Si bien 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 un Assert.xyz o algo que es mucho menos kludgy y mucho más en el espíritu de JUnit para este tipo de situaciones.

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

Editar Ahora que JUnit5 ha 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 la Regla de ExpectedException Exception:

 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 se lanza foo.doStuff() antes de foo.doStuff()

Ver este artículo para más detalles

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

Tiendo a usar esto para probar la validación de parámetros, ya que estos métodos suelen ser muy simples, pero las pruebas más complejas se pueden realizar mejor con:

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

Aplica juicio.

Como se contestó anteriormente, hay muchas formas de tratar las excepciones en JUnit. Pero con Java 8 hay otro: usar Lambda Expressions. Con Lambda Expressions podemos lograr una syntax 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.

Esta es una técnica relativamente simple pero poderosa.

Eche un vistazo a esta publicación de 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.

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

  • para junit4.x, use el atributo opcional ‘esperado’ de la anotación de prueba

     @Test(expected = IndexOutOfBoundsException.class) public void testFooThrowsIndexOutOfBoundsException() { foo.doStuff(); } 
  • para junit4.x, use 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 el modo clásico try / catch ampliamente utilizado en el marco de junit 3

     @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 puedes usar assertThrows como sigue

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

    • la primera forma se usa cuando solo desea probar el tipo de excepción
    • las otras tres formas se usan cuando desea enviar un mensaje de excepción de prueba
    • si usas junit 3, entonces el tercero es preferido
    • si te gusta junit 5, entonces te gustará el 4to
  • para obtener más información, puede leer este documento y la guía del usuario de junit5 para obtener más información.

tl; dr

  • pre-JDK8: recomendaré el viejo buen trycatch block.

  • post-JDK8: use AssertJ o lambdas personalizados 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 trycatch block o use las herramientas JUnit ( @Test(expected = ...) o la función @Rule ExpectedException JUnit rule).

Pero de esta manera no son tan elegantes y no combinan bien la legibilidad con otras herramientas.

  1. El bloque trycatch tiene que escribir el bloque alrededor del comportamiento probado y escribir la aserción en el bloque catch, eso puede estar bien, pero muchos encuentran que este estilo interrumpe el flujo de lectura de una prueba. También debe escribir un Assert.fail al final del bloque try contrario, la prueba puede pasar por alto un lado de las aserciones; PMD , findbugs o Sonar detectarán estos 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 encoding. Pero a este enfoque le faltan 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 precisa puede no ser suficiente).
    • Además, a medida que se pone la expectativa en el método, dependiendo de cómo se haya escrito el código probado, la parte incorrecta del código de prueba puede arrojar la excepción, dando lugar a una prueba de falso positivo y no estoy seguro de que PMD , findbugs o Sonar den consejos 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 bash de corregir las advertencias previas, pero se siente un poco incómodo de usar, ya que utiliza un estilo de expectativa, los usuarios de EasyMock conocen muy bien este estilo. Puede ser conveniente para algunos, pero si sigue los principios de Desarrollo impulsado por comportamiento (BDD) o Organizar acuerdo de acto (AAA), la regla ExpectedException no encajará en ese estilo de escritura. Aparte de eso, puede sufrir el mismo problema que el modo @Test , dependiendo de dónde coloque 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 statement de la prueba, rompe su flujo de lectura si las pruebas siguen BDD o AAA.

    También vea este problema de comentarios en JUnit del autor de ExpectedException .

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

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

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

    Un rápido ejemplo 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 muy sencillo, capta la excepción en una línea específica, la API then es un alias que usará las API AssertJ (similar al uso de assertThat(ex).hasNoCause()... ). En algún momento, el proyecto se basó en FEST-Assert el antecesor de AssertJ . EDIT: parece que el proyecto está elaborando un soporte Java 8 Lambdas.

    Actualmente esta biblioteca tiene dos deficiencias:

    • En el momento de escribir estas líneas, vale la pena mencionar que esta biblioteca se basa en Mockito 1.x ya que crea una simulación del objeto probado detrás de la escena. Como Mockito aún no está actualizado, esta biblioteca no puede funcionar con clases finales o métodos finales . E incluso si estaba basado en mockito 2 en la versión actual, esto requeriría declarar un generador de simulacros global ( inline-mock-maker ), algo que puede no ser lo que usted desea, ya que este modificador tiene diferentes inconvenientes que el simulacro habitual.

    • Requiere otra dependencia de prueba.

    Estos problemas no se aplicarán una vez que la biblioteca admita lambdas, sin embargo, la funcionalidad se duplicará con el conjunto de herramientas AssertJ.

    Teniendo todo en cuenta si no quieres usar la herramienta de excepción de captura, te recomendaré la buena manera antigua del bloque trycatch , al menos hasta el JDK7. Y para los usuarios de JDK 8, es posible que prefiera utilizar AssertJ, ya que ofrece mucho más que simplemente hacer 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 buena API fluida 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 una reescritura casi completa de JUnit 5, las afirmaciones se han mejorado un poco, pueden resultar interesantes como una forma original de afirmar adecuadamente la excepción. Pero realmente la afirmación API es aún un poco pobre, no hay nada afuera de assertThrows .

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

    Como ha notado, assertEquals todavía está volviendo void y, como tal, no permite encadenar afirmaciones como AssertJ.

    Además, si recuerda el choque de nombre con Matcher o Assert , prepárese para enfrentar el mismo choque con las Assertions .

Me gustaría concluir que hoy (2017-03-03) la facilidad de uso de AssertJ , su API reconocible , su rápido ritmo de desarrollo y su dependencia de prueba de facto es la mejor solución con JDK8 independientemente del marco de prueba (JUnit o no), los JDK anteriores deberían confiar en catch bloques de try y catch , incluso si se sienten torpes.

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

Qué tal esto: capte una excepción muy general, asegúrese de que salga del bloque catch, luego afirme que la clase de la excepción es lo que espera que sea. Esta afirmación fallará si a) la excepción es del tipo incorrecto (por ejemplo, si obtuvo un puntero nulo en su lugar) yb) nunca se lanzó la excepción.

 public void testFooThrowsIndexOutOfBoundsException() { Throwable e = null; try { foo.doStuff(); } catch (Throwable ex) { e = ex; } assertTrue(e instanceof IndexOutOfBoundsException); } 

Solución de estilo BDD : JUnit 4 + Catch Exception + 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 

Usando una aserción de 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 que la línea esperada en la prueba lanzó la excepción y le permite verificar más detalles acerca de la excepción, como el mensaje, más fácil:

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

Maven / Gradle instrucciones aquí.

Para resolver el mismo problema, establecí 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.

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

Aquí hay un ejemplo que verifica que se lanza una excepción, y usa Truth para hacer afirmaciones en 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. Obtiene un mensaje de excepción útil si el código en el lambda no arroja una excepción, y un stacktrace si arroja 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 arrojar la excepción
  6. No necesita enumerar la excepción esperada en la cláusula throws
  7. Puede usar el marco de afirmación de su elección para hacer afirmaciones sobre la excepción detectada

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

Actualización: JUnit5 tiene una mejora para las pruebas de excepciones: assertThrows .

El siguiente ejemplo es de: Guía de 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 formas de probar que se lanza una excepción. También he discutido las siguientes opciones en mi publicación Cómo escribir excelentes pruebas unitarias con JUnit

Establezca 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!")); } } 

Prueba 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"); } 

Puede leer más sobre las pruebas de excepciones en JUnit4 wiki para Exception testing y bad.robot – Expecteding Exceptions JUnit Rule .

También puedes hacer esto:

 @Test public void testFooThrowsIndexOutOfBoundsException() { try { foo.doStuff(); assert false; } catch (IndexOutOfBoundsException e) { assert true; } } 

En mi humilde opinión, la mejor manera de verificar 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.

Solución 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

Probé muchos de los métodos aquí, pero fueron complicados o no cumplieron con mis requisitos. De hecho, uno puede escribir un método de ayuda bastante simple:

 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; } } 

Úselo así:

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

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

JUnit tiene soporte incorporado para esto, con un atributo “esperado”

Solución Java 8

Si desea una solución que:

  • Utiliza Java 8 lambdas
  • No depende de ninguna magia JUnit
  • Le permite verificar múltiples excepciones dentro de un solo método de prueba
  • Comprueba que una excepción sea 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
  • Establece el objeto de excepción real que se lanzó para que pueda examinarlo más a fondo

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

 public final  T expectException( Class 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 )

Úselo de la siguiente manera:

 @Test public void testThrows() { RuntimeException e = expectException( RuntimeException.class, () -> { throw new RuntimeException( "fail!" ); } ); assert e.getMessage().equals( "fail!" ); } 

En mi caso, siempre recibo RuntimeException de db, pero los mensajes son diferentes. 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)); } 

In JUnit 4 or later you can test the exceptions as follows

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

this provides a lot of features which can be used to improve our JUnit tests.
If you see the below example I am testing 3 things on the exception.

  1. The Type of exception thrown
  2. The exception Message
  3. The cause of the exception

 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.equalTo(exceptionCause)); classUnderTest.methodUnderTest("param1", "param2"); } } 

We can use an assertion fail after the method that must return an exception:

 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()); } 

The most flexible and elegant answer for Junit 4 I found in the Mkyoung blog . It have the flexibility of the try/catch using the @Rule annotation. I liked this approach because I already needed to read specific attributes of a customized exception.

 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(""); } } 

Additionally to what NamShubWriter has said, make sure that:

  • The ExpectedException instance is public ( Related Question )
  • The ExpectedException isn’t instantiated in say, the @Before method. This post clearly explains all the intricacies of JUnit’s order of execution.

Do not do this:

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

Finally, this blog post clearly illustrates how to assert that a certain exception is thrown.

Just make a Matcher that can be turned off and on, like this:

 public class ExceptionMatcher extends BaseMatcher { private boolean active = true; private Class throwable; public ExceptionMatcher(Class 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:

add public ExpectedException exception = ExpectedException.none(); , then:

 ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class); exception.expect(exMatch); someObject.somethingThatThrowsMyException(); exMatch.off(); 

Take for example, you want to write Junit for below mentioned code fragment

 public int divideByZeroDemo(int a,int b){ return a/b; } public void exceptionWithMessage(String [] arr){ throw new ArrayIndexOutOfBoundsException("Array is out of bound"); } 

The above code is to test for some unknown exception that may occur and the below one is to assert some exception with custom message.

  @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"}); } 

With Java 8 you can create a method taking a code to check and expected exception as parameters:

 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); } } 

and then inside your test:

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

Beneficios:

  • not relying on any library
  • localised check – more precise and allows to have multiple assertions like this within one test if needed
  • easy to use

My solution using Java 8 lambdas:

 public static  T assertThrows(Class 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 } } } 

You have to define a FunctionalInterface, because Runnable doesn’t declare the required throws .

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

The method can be used as follows:

 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); 

There are two ways of writing test case

  1. Annotate the test with the exception which is thrown by the method. Something like this @Test(expected = IndexOutOfBoundsException.class)
  2. You can simply catch the exception in the test class using the try catch block and assert on the message that is thrown from the method in test class.

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

I hope this answers your query Happy learning…

Junit4 solution with Java8 is to use this function:

 public Throwable assertThrows(Class 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)); } 

Usage is then:

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

Note that the only limitation is to use a final object reference in lambda expression. This solution allows to continue test assertions instead of expecting thowable at method level using @Test(expected = IndexOutOfBoundsException.class) solution.

I recomend library assertj-core to handle exception in junit test

In java 8, like this:

 //given //when Throwable throwable = catchThrowable(() -> anyService.anyMethod(object)); //then AnyException anyException = (AnyException) throwable; assertThat(anyException.getMessage()).isEqualTo("........"); assertThat(exception.getCode()).isEqualTo(".......); 
    Intereting Posts