¿Cómo puedo usar JUnit4 idiomáticamente para probar que algún código arroja una excepción?
Si bien 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 un Assert.xyz o algo que es mucho menos grosero y mucho más en el espíritu de JUnit para este tipo de situaciones.
org.mockito.Mockito.verify
con varios parámetros para asegurarme de que ocurrieron ciertas cosas (de modo que se llamó a un servicio de registro con los parámetros correctos) antes de que se lanzara la excepción.Respuestas:
Depende de la versión de JUnit y de las bibliotecas de afirmaciones que use.
La respuesta original para
JUnit <= 4.12
fue:Aunque la respuesta https://stackoverflow.com/a/31826781/2986984 tiene más opciones para JUnit <= 4.12.
Referencia:
fuente
ArrayList
respondaget()
es irrelevante. Si en el futuro decidiera pasar a una matriz primitiva, tendría que cambiar esta implementación de prueba. La estructura de datos debe estar oculta, de modo que la prueba pueda centrarse en el comportamiento de la clase .Editar: ahora que se han lanzado JUnit 5 y JUnit 4.13, la mejor opción sería usar
Assertions.assertThrows()
(para JUnit 5) yAssert.assertThrows()
(para JUnit 4.13). Vea mi otra respuesta para más detalles.Si no ha migrado a JUnit 5, pero puede usar JUnit 4.7, puede usar la
ExpectedException
Regla:Esto es mucho mejor que
@Test(expected=IndexOutOfBoundsException.class)
porque la prueba fallará siIndexOutOfBoundsException
se lanza antesfoo.doStuff()
Vea este artículo para más detalles.
fuente
ExpectedException
clase tiene formas de hacer coincidir el mensaje de la excepción, o incluso escribir su propio marcador que depende de la clase de excepción. En segundo lugar, puede establecer sus expectativas inmediatamente antes de la línea de código que espera lanzar la excepción, lo que significa que su prueba fallará si la línea de código incorrecta arroja la excepción; mientras que no hay forma de hacerlo con la solución de skaffman.Tenga cuidado al usar la excepción esperada, porque solo afirma que el método arrojó esa excepción, no una línea de código particular en la prueba.
Tiendo a usar esto para probar la validación de parámetros, porque tales métodos son generalmente muy simples, pero las pruebas más complejas podrían ser mejor:
Aplica el juicio.
fuente
ExpectedException
, lo normal es establecer la expectativa inmediatamente antes de la línea que espera lanzar la excepción. De esa manera, si una línea anterior arroja la excepción, no activará la regla y la prueba fallará.Como se respondió anteriormente, hay muchas formas de tratar las excepciones en JUnit. Pero con Java 8 hay otro: usar expresiones Lambda. Con Lambda Expressions podemos lograr una sintaxis como esta:
ClaimThrown acepta una interfaz funcional, cuyas instancias se pueden crear con expresiones lambda, referencias de métodos o referencias de constructor. afirmar que 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.
fuente
new DummyService()::someMethod
es unMethodHandle
, pero este enfoque funciona igualmente bien con expresiones lambda.En junio, hay cuatro formas de probar la excepción.
junit5.x
para junit5.x, puede usar
assertThrows
lo siguientejunit4.x
para junit4.x, use el atributo opcional 'esperado' de la anotación de prueba
para junit4.x, use la regla ExpectedException
También puede usar el clásico método try / catch ampliamente utilizado en el marco del junit 3
entonces
Para obtener más información, puede leer este documento y la guía del usuario de junit5 para obtener más información.
fuente
Trowable
al métodoExpectedException.expect
. Por favor vea su firma . @miusertl; dr
post-JDK8: use AssertJ o lambdas personalizadas para afirmar un comportamiento excepcional .
pre-JDK8: Voy a recomendar la vieja buena
try
-catch
bloque. ( No olvides agregar unafail()
afirmación antes delcatch
bloque )Independientemente de Junit 4 o JUnit 5.
la larga historia
Es posible escribir usted mismo y hacerlo usted mismo
try
:catch
bloquee o use las herramientas JUnit (@Test(expected = ...)
o la@Rule ExpectedException
función de regla JUnit).Pero estas formas no son tan elegantes y no combinan bien la legibilidad con otras herramientas. Además, las herramientas JUnit tienen algunas dificultades.
El bloque
try
-catch
tiene que escribir el bloque alrededor del comportamiento probado y escribir la afirmación en el bloque catch, eso puede estar bien, pero muchos encuentran que este estilo interrumpe el flujo de lectura de una prueba. Además, debe escribir unAssert.fail
al final deltry
bloque. De lo contrario, la prueba puede perder un lado de las afirmaciones; PMD , findbugs o Sonar detectarán tales problemas.La
@Test(expected = ...)
característica 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 es deficiente en algunas áreas.Además, como la expectativa se coloca en el método, dependiendo de cómo se escriba el código probado, la parte incorrecta del código de prueba puede arrojar la excepción, lo que lleva a una prueba de falso positivo y no estoy seguro de que PMD , findbugs o Sonar dará pistas sobre dicho código.
La
ExpectedException
regla también es un intento de arreglar las advertencias anteriores, pero se siente un poco incómodo de usar ya que usa 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 Conducido por el Comportamiento (BDD) o Arrange Act Assert (AAA), laExpectedException
regla no encajará en ese estilo de escritura. Aparte de eso, puede sufrir el mismo problema que el@Test
camino, dependiendo de dónde coloque la expectativa.Incluso la excepción esperada se coloca antes de la declaración de prueba, interrumpe su flujo de lectura si las pruebas siguen BDD o AAA.
Además, vea este comentario en JUnit del autor de
ExpectedException
. JUnit 4.13-beta-2 incluso desprecia este mecanismo:Por lo tanto, estas opciones anteriores tienen toda su carga de advertencias, y claramente no son inmunes a los errores del codificador.
Hay un proyecto del que me di cuenta después de crear esta respuesta que parece prometedor, es una excepción .
Como dice la descripción del proyecto, permitió que un codificador escribiera en una línea fluida de código para detectar la excepción y ofrecer esta excepción para la última afirmación. Y puede usar cualquier biblioteca de aserciones como Hamcrest o AssertJ .
Un ejemplo rápido tomado de la página de inicio:
Como puede ver, el código es realmente sencillo, detecta la excepción en una línea específica, la
then
API es un alias que usará API AssertJ (similar a usarassertThat(ex).hasNoCause()...
). En algún momento, el proyecto se basó en FEST-Assert, el antepasado de AssertJ . EDITAR: Parece que el proyecto está gestando un soporte para Java 8 Lambdas.Actualmente, esta biblioteca tiene dos deficiencias:
Al momento de escribir esto, es digno de mención decir 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 todavía no está actualizado, esta biblioteca no puede funcionar con clases finales o métodos finales . E incluso si se basara en Mockito 2 en la versión actual, esto requeriría declarar un creador de simulacros global (
inline-mock-maker
), algo que puede no ser lo que desea, ya que este simulador tiene diferentes inconvenientes que el creador de simulacros regular.Requiere otra dependencia de prueba.
Estos problemas no se aplicarán una vez que la biblioteca admita lambdas. Sin embargo, la funcionalidad será duplicada por el conjunto de herramientas AssertJ.
Teniendo todo en cuenta si no desea utilizar la herramienta de captura de excepciones, recomendaré la antigua y buena forma del bloque
try
-catch
, 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.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 y agradable para afirmar un comportamiento excepcional.
Y una prueba de muestra con AssertJ :
Con una reescritura casi completa de JUnit 5, las afirmaciones se han mejorado un poco, pueden resultar interesantes como una forma inmediata de afirmar correctamente la excepción. Pero realmente la API de afirmación sigue siendo un poco pobre, no hay nada afuera
assertThrows
.Como notaron,
assertEquals
todavía está regresandovoid
, y como tal no permite encadenar afirmaciones como AssertJ.Además, si recuerda el choque de nombres con
Matcher
oAssert
, prepárese para enfrentar el mismo choque conAssertions
.Me gustaría concluir que hoy (2017-03-03) la facilidad de uso de AssertJ , la API reconocible , 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 JDK anteriores, deben confiar en su lugar
try
-catch
bloques, incluso si se sienten torpe.Esta respuesta ha sido copiada de otra pregunta que no tiene la misma visibilidad, soy el mismo autor.
fuente
Ahora que se han lanzado JUnit 5 y JUnit 4.13, la mejor opción sería usar
Assertions.assertThrows()
(para JUnit 5) yAssert.assertThrows()
(para JUnit 4.13). Consulte la Guía del usuario de Junit 5 .Aquí hay un ejemplo que verifica que se produce una excepción y usa la Verdad para hacer afirmaciones en el mensaje de excepción:
Las ventajas sobre los enfoques en las otras respuestas son:
throws
cláusulaSe agregará un método similar
org.junit Assert
en JUnit 4.13.fuente
Qué tal esto: Capture 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) la excepción nunca se lanzó.
fuente
assertEquals(ExpectedException.class, e.getClass())
le mostrará los valores esperados y reales cuando la prueba falle.Solución de estilo BDD : JUnit 4 + Catch Exception + AssertJ
Dependencias
fuente
Usando una aserción AssertJ , que se puede usar junto con JUnit:
Es mejor que
@Test(expected=IndexOutOfBoundsException.class)
porque garantiza que la línea esperada en la prueba arrojó la excepción y le permite verificar más detalles sobre la excepción, como el mensaje, más fácil:Instrucciones de Maven / Gradle aquí.
fuente
assertThat
, siempre el AssertJ. Además, el método JUnit devuelve solo un tipo "regular", mientras que el método AssertJ devuelve unaAbstractAssert
subclase ... que permite la secuencia de métodos como anteriormente (o los términos técnicos para esto ...).Para resolver el mismo problema, configuré un pequeño proyecto: http://code.google.com/p/catch-exception/
Usando este pequeño ayudante escribirías
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.
fuente
foo
esfinal
que se producirá un error porque no se puede Proxyfoo
?Actualización: JUnit5 tiene una mejora para probar las excepciones:
assertThrows
.el siguiente ejemplo es de: Junit 5 Guía del usuario
Respuesta original usando JUnit 4.
Hay varias formas de probar que se produce una excepción. También he discutido las siguientes opciones en mi publicación Cómo escribir excelentes pruebas unitarias con JUnit
Establece el
expected
parámetro@Test(expected = FileNotFoundException.class)
.Utilizando
try
catch
Prueba con
ExpectedException
regla.Puede leer más sobre las pruebas de excepciones en JUnit4 wiki para pruebas de excepción y bad.robot - Regla de JUnit de excepciones de excepción .
fuente
También puedes hacer esto:
fuente
Assert.fail()
, noassert
, solo en caso de que sus pruebas se ejecuten en un entorno donde las aserciones no están habilitadas.En mi humilde opinión, la mejor manera de verificar las excepciones en JUnit es el patrón try / catch / fail / afirmar:
El
assertTrue
podría ser un poco fuerte para algunas personas, por lo queassertThat(e.getMessage(), containsString("the message");
podría ser preferible.fuente
Solución JUnit 5
Más información sobre JUnit 5 en http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
fuente
expectThrows()
es una parte TestNG, no un JUnitLa respuesta más flexible y elegante para Junit 4 la encontré en el blog de Mkyong . Tiene la flexibilidad de
try/catch
usar la@Rule
anotación. Me gusta este enfoque porque puedes leer atributos específicos de una excepción personalizada.fuente
Probé muchos de los métodos aquí, pero eran complicados o no cumplían con mis requisitos. De hecho, uno puede escribir un método auxiliar simplemente:
Úselo así:
Cero dependencias: no necesita mockito, no necesita powermock; y funciona bien con las clases finales.
fuente
Solución Java 8
Si desea una solución que:
Aquí hay una función de utilidad que escribí:
( tomado de mi blog )
Úselo de la siguiente manera:
fuente
JUnit tiene soporte incorporado para esto, con un atributo "esperado"
fuente
En mi caso, siempre obtengo RuntimeException de db, pero los mensajes difieren. Y la excepción debe ser manejada respectivamente. Así es como lo probé:
fuente
} catch (
, debe insertarfail("no exception thrown");
Simplemente haga un Matcher que se pueda apagar y encender de esta manera:
Para usarlo:
agregar
public ExpectedException exception = ExpectedException.none();
, entonces:fuente
En JUnit 4 o posterior, puede probar las excepciones de la siguiente manera
Esto proporciona muchas características que se pueden utilizar para mejorar nuestras pruebas JUnit.
Si ve el siguiente ejemplo, estoy probando 3 cosas en la excepción.
fuente
Podemos usar un error de aserción después del método que debe devolver una excepción:
fuente
catch
se tragaría el rastro de la pila si se lanza alguna otra excepción, perdiendo información útilAdemás de lo que NamShubWriter ha dicho, asegúrese de que:
No no hacer esto:
Finalmente, esta publicación de blog ilustra claramente cómo afirmar que se produce una cierta excepción.
fuente
Recomiendo la biblioteca
assertj-core
para manejar la excepción en prueba junitEn java 8, así:
fuente
La solución de Junit4 con Java8 es usar esta función:
El uso es entonces:
Tenga en cuenta que la única limitación es utilizar una
final
referencia de objeto en la expresión lambda. Esta solución permite continuar con las aserciones de prueba en lugar de esperar que sea posible a nivel de método utilizando la@Test(expected = IndexOutOfBoundsException.class)
solución.fuente
Tomemos, por ejemplo, que desea escribir Junit para el fragmento de código mencionado a continuación
El código anterior es para probar alguna excepción desconocida que pueda ocurrir y el siguiente es afirmar alguna excepción con un mensaje personalizado.
fuente
Aquí hay otra forma de verificar si el método arrojó la excepción correcta o no.
fuente
JUnit framework tiene
assertThrows()
método:org.junit.jupiter.api.Assertions
clase;org.junit.Assert
clase;org.junit.jupiter:junit-jupiter-api
a su proyecto y obtendrá una versión perfectamente funcional de JUnit 5.fuente
Con Java 8 puede crear un método tomando un código para verificar y la excepción esperada como parámetros:
y luego dentro de tu prueba:
Beneficios:
fuente