try test jupiter expected example catch assertthrows java exception exception-handling junit

java - expected - junit jupiter test exception



En Java, ¿cómo puedo validar una excepción lanzada con JUnit? (10)

@akuhn:

Incluso sin cierres, podemos obtener una solución más legible (usando catch-exception ):

import static com.googlecode.catchexception.CatchException.*; public void test() { ... ... catchException(nastyBoy).doNastyStuff(); assertTrue(caughtException() instanceof WhateverException); assertEquals("Message", caughtException().getMessage()); }

Al escribir pruebas unitarias para una API Java, puede haber circunstancias en las que desee realizar una validación más detallada de una excepción. Es decir, más de lo que ofrece la anotación @test que ofrece JUnit.

Por ejemplo, considere una clase que debe atrapar una excepción de alguna otra interfaz, ajuste esa excepción y ejecute la excepción envuelta. Es posible que desee verificar:

  1. La llamada al método exacto que arroja la excepción envuelta.
  2. Que la excepción envoltura tiene la excepción original como causa.
  3. El mensaje de la excepción de contenedor.

El punto principal aquí es que desea realizar una validación adicional de una excepción en una prueba unitaria (no un debate sobre si debe verificar cosas como el mensaje de excepción).

¿Cuál es un buen enfoque para esto?


Al mirar las respuestas propuestas, realmente puede sentir el dolor de no tener cierres en Java. En mi humilde opinión, la solución más fácil de leer es la captura de prueba.

@Test public void test() { ... ... try { ... fail("No exception caught :("); } catch (RuntimeException ex) { assertEquals(Whatever.class, ex.getCause().getClass()); assertEquals("Message", ex.getMessage()); } }


Como se proporciona en su respuesta , es un buen enfoque. Además de esto:

Puede ajustar la función expectException en una nueva Anotación, llamada ExpectedException .
Un método anotado se vería así:

@Test @ExpectedException(class=WrapperException.class, message="Exception Message", causeException) public void testAnExceptionWrappingFunction() { //whatever you test }

De esta forma sería más legible, pero es exactamente el mismo enfoque.

Otra razón es: me gustan las anotaciones :)


El siguiente método de ayuda (adaptado de this publicación de blog) hace el truco:

/** * Run a test body expecting an exception of the * given class and with the given message. * * @param test To be executed and is expected to throw the exception. * @param expectedException The type of the expected exception. * @param expectedMessage If not null, should be the message of the expected exception. * @param expectedCause If not null, should be the same as the cause of the received exception. */ public static void expectException( Runnable test, Class<? extends Throwable> expectedException, String expectedMessage, Throwable expectedCause) { try { test.run(); } catch (Exception ex) { assertSame(expectedException, ex.getClass()); if (expectedMessage != null) { assertEquals(expectedMessage, ex.getMessage()); } if (expectedCause != null) { assertSame(expectedCause, ex.getCause()); } return; } fail("Didn''t find expected exception of type " + expectedException.getName()); }

El código de prueba puede invocar esto de la siguiente manera:

TestHelper.expectException( new Runnable() { public void run() { classInstanceBeingTested.methodThatThrows(); } }, WrapperException.class, "Exception Message", causeException );


En JUnit 4 se puede hacer fácilmente usando la regla ExpectedException .

Aquí hay un ejemplo de javadocs:

// These tests all pass. public static class HasExpectedException { @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void throwsNothing() { // no exception expected, none thrown: passes. } @Test public void throwsNullPointerException() { thrown.expect(NullPointerException.class); throw new NullPointerException(); } @Test public void throwsNullPointerExceptionWithMessage() { thrown.expect(NullPointerException.class); thrown.expectMessage("happened?"); thrown.expectMessage(startsWith("What")); throw new NullPointerException("What happened?"); } }


Hasta este momento, hice mi validación de excepción al hacer esto:

try { myObject.doThings(); fail("Should''ve thrown SomeException!"); } catch (SomeException e) { assertEquals("something", e.getSomething()); }

Sin embargo, dediqué algunos momentos a pensar en el problema y obtuve lo siguiente (Java5, JUnit 3.x):

// Functor interface for exception assertion. public interface AssertionContainer<T extends Throwable> { void invoke() throws T; void validate(T throwable); Class<T> getType(); } // Actual assertion method. public <T extends Throwable> void assertThrowsException(AssertionContainer<T> functor) { try { functor.invoke(); fail("Should''ve thrown "+functor.getType()+"!"); } catch (Throwable exc) { assertSame("Thrown exception was of the wrong type! Expected "+functor.getClass()+", actual "+exc.getType(), exc.getClass(), functor.getType()); functor.validate((T) exc); } } // Example implementation for servlet I used to actually test this. It was an inner class, actually. AssertionContainer<ServletException> functor = new AssertionContainer<ServletException>() { public void invoke() throws ServletException { servlet.getRequiredParameter(request, "some_param"); } public void validate(ServletException e) { assertEquals("Parameter /"some_param/" wasn''t found!", e.getMessage()); } public Class<ServletException> getType() { return ServletException.class; } } // And this is how it''s used. assertThrowsException(functor);

Al mirar a estos dos no puedo decidir cuál me gusta más. Supongo que este es uno de esos problemas en los que el logro de un objetivo (en mi caso, el método de aserción con el parámetro de functor) no vale la pena a largo plazo, ya que es mucho más fácil hacer esos 6+ de código para afirmar el intento Bloque de captura.

Por otra parte, tal vez mi resultado de 10 minutos de resolución de problemas el viernes por la noche no sea la forma más inteligente de hacerlo.


Hice algo muy simple

testBla(){ try { someFailingMethod() fail(); //method provided by junit } catch(Exception e) { //do nothing } }


Hice un ayudante similar a los otros publicados:

public class ExpectExceptionsExecutor { private ExpectExceptionsExecutor() { } public static void execute(ExpectExceptionsTemplate e) { Class<? extends Throwable> aClass = e.getExpectedException(); try { Method method = ExpectExceptionsTemplate.class.getMethod("doInttemplate"); method.invoke(e); } catch (NoSuchMethodException e1) { throw new RuntimeException(); } catch (InvocationTargetException e1) { Throwable throwable = e1.getTargetException(); if (!aClass.isAssignableFrom(throwable.getClass())) { // assert false fail("Exception isn''t the one expected"); } else { assertTrue("Exception captured ", true); return; } ; } catch (IllegalAccessException e1) { throw new RuntimeException(); } fail("No exception has been thrown"); } }

Y la plantilla que el cliente debería implementar

public interface ExpectExceptionsTemplate<T extends Throwable> { /** * Specify the type of exception that doInttemplate is expected to throw * @return */ Class<T> getExpectedException(); /** * Execute risky code inside this method * TODO specify expected exception using an annotation */ public void doInttemplate(); }

Y el código del cliente sería algo como esto:

@Test public void myTest() throws Exception { ExpectExceptionsExecutor.execute(new ExpectExceptionsTemplate() { @Override public Class getExpectedException() { return IllegalArgumentException.class; } @Override public void doInttemplate() { riskyMethod.doSomething(null); } }); }

Parece realmente prolijo, pero si usa un IDE con buena autocompletación, solo necesitará escribir el tipo de excepción y el código real bajo prueba. (El resto lo hará el IDE: D)


Para JUnit 5 es mucho más fácil:

@Test void testAppleIsSweetAndRed() throws Exception { IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, () -> testClass.appleIsSweetAndRed("orange", "red", "sweet")); assertEquals("this is the exception message", ex.getMessage()); assertEquals(NullPointerException.class, ex.getCause().getClass()); }

Al devolver el objeto de excepción en sí, assertThrows() permite probar todos los aspectos relacionados con sus excepciones lanzadas.


Para JUNIT 3.x

public void test(){ boolean thrown = false; try{ mightThrowEx(); } catch ( Surprise expected ){ thrown = true; assertEquals( "message", expected.getMessage()); } assertTrue(thrown ); }