Sé que una forma de hacerlo sería:
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
¿Hay alguna forma más limpia de hacer esto? (¿Probablemente usando Junit's @Rule
?)
java
unit-testing
junit
exception-handling
junit4
Ankit Dhingra
fuente
fuente
Respuestas:
Te estás acercando a esto de la manera incorrecta. Simplemente pruebe su funcionalidad: si se produce una excepción, la prueba fallará automáticamente. Si no se produce ninguna excepción, todas sus pruebas se volverán verdes.
He notado que esta pregunta genera interés de vez en cuando, así que me expandiré un poco.
Antecedentes de las pruebas unitarias
Cuando realiza pruebas unitarias, es importante que se defina lo que considera una unidad de trabajo. Básicamente: una extracción de su base de código que puede o no incluir múltiples métodos o clases que representan una sola pieza de funcionalidad.
O, como se define en The art of Unit Testing, 2nd Edition de Roy Osherove , página 11:
Lo importante es darse cuenta de que una unidad de trabajo generalmente no es solo un método, sino que en el nivel más básico es un método y luego se encapsula en otra unidad de trabajo.
Idealmente, debe tener un método de prueba para cada unidad de trabajo por separado para que siempre pueda ver de inmediato dónde van las cosas mal. En este ejemplo, hay un método básico llamado
getUserById()
que devolverá un usuario y hay un total de 3 unidades de trabajo.La primera unidad de trabajo debe probar si se devuelve o no un usuario válido en el caso de una entrada válida o no válida.
Aquí se deben manejar las excepciones lanzadas por el origen de datos: si no hay ningún usuario presente, debe haber una prueba que demuestre que se produce una excepción cuando no se puede encontrar al usuario. Una muestra de esto podría ser la
IllegalArgumentException
que se captura con la@Test(expected = IllegalArgumentException.class)
anotación.Una vez que haya manejado todos sus casos de uso para esta unidad básica de trabajo, sube de nivel. Aquí haces exactamente lo mismo, pero solo manejas las excepciones que provienen del nivel justo debajo del actual. Esto mantiene su código de prueba bien estructurado y le permite ejecutar rápidamente la arquitectura para encontrar dónde van las cosas mal, en lugar de tener que saltar por todas partes.
Manejo de una entrada válida y defectuosa de las pruebas
En este punto, debería quedar claro cómo manejaremos estas excepciones. Hay 2 tipos de entrada: entrada válida y entrada defectuosa (la entrada es válida en sentido estricto, pero no es correcta).
Cuando trabaja con una entrada válida , está estableciendo la expectativa implícita de que cualquier prueba que escriba funcionará.
Tal llamada al método puede tener este aspecto:
existingUserById_ShouldReturn_UserObject
. Si este método falla (por ejemplo, se produce una excepción), entonces sabe que algo salió mal y puede comenzar a cavar.Al agregar otra prueba (
nonExistingUserById_ShouldThrow_IllegalArgumentException
) que usa la entrada defectuosa y espera una excepción, puede ver si su método hace lo que se supone que debe hacer con una entrada incorrecta.TL; DR
Intentaba hacer dos cosas en su prueba: verificar la entrada válida y defectuosa. Al dividir esto en dos métodos para que cada uno haga una cosa, tendrá pruebas mucho más claras y una visión general mucho mejor de dónde van las cosas mal.
Al tener en cuenta la unidad de trabajo en capas, también puede reducir la cantidad de pruebas que necesita para una capa que es más alta en la jerarquía porque no tiene que tener en cuenta todo lo que podría haber salido mal en las capas inferiores: las capas debajo de la actual son una garantía virtual de que sus dependencias funcionan y si algo sale mal, está en su capa actual (suponiendo que las capas inferiores no arrojen ningún error).
fuente
expected
anotación. Si desea probar un escenario en el que falla su código y desea ver si el error se maneja correctamente: useexpected
y tal vez use aserciones para determinar si se ha resuelto.throws IllegalArgumentException
a tu prueba. Lo que quiere al final, es que su prueba se ponga roja si hay una excepción. ¿Bien adivina que? No necesitas escribirfail()
. Como escribió @Jeroen Vannevel: "si se produce una excepción, la prueba fallará automáticamente".Me topé con esto debido a la regla de SonarQube "calamar: S2699": "Agregue al menos una afirmación a este caso de prueba".
Tuve una prueba simple cuyo único objetivo era pasar sin lanzar excepciones.
Considere este código simple:
¿Qué tipo de afirmación se puede agregar para probar este método? Claro, puedes hacer un intento de atraparlo, pero eso es solo una acumulación de código.
La solución proviene de JUnit en sí.
En caso de que no se produzca ninguna excepción y desee ilustrar explícitamente este comportamiento, simplemente agregue
expected
como en el siguiente ejemplo:Test.None.class
es el valor predeterminado para el valor esperado.fuente
Con afirmaciones fluidas AssertJ 3.7.0 :
fuente
JUnit 5 (Júpiter) proporciona tres funciones para verificar la ausencia / presencia de excepción:
●
assertAll()
Afirma que todos los suministrados
executables
no arrojan excepciones.
●
assertDoesNotThrow()
Afirma que la ejecución del
suministrado
executable
/supplier
no arroja ningún tipo de excepción .
Esta función está disponible
desde JUnit 5.2.0 (29 de abril de 2018).
●
assertThrows()
Afirma que la ejecución de los
executable
lanzamientos suministrados genera una excepción
expectedType
y devuelve la excepción .
Ejemplo
fuente
Java 8 hace esto mucho más fácil, y Kotlin / Scala doblemente.
Podemos escribir una pequeña clase de utilidad
y luego tu código se vuelve simplemente:
Si no tiene acceso a Java-8, usaría una instalación java dolorosamente antigua: bloques de código arbitrario y un simple comentario
Y finalmente, con kotlin, un idioma del que me he enamorado recientemente:
Aunque hay mucho espacio para jugar con exactamente cómo quieres expresar esto, siempre fui un fanático de las afirmaciones fluidas .
Respecto a
Esto es correcto en principio pero incorrecto en conclusión.
Java permite excepciones para el flujo de control. Esto se hace por el mismo tiempo de ejecución JRE en las API como
Double.parseDouble
a través de unNumberFormatException
ePaths.get
través de unaInvalidPathException
.Dado que ha escrito un componente que valida las cadenas de números para
Double.ParseDouble
, tal vez utilizando un Regex, tal vez un analizador escrito a mano, o tal vez algo que incorpore otras reglas de dominio que restrinjan el rango de un doble a algo específico, la mejor manera de probar esto ¿componente? Creo que una prueba obvia sería afirmar que, cuando se analiza la cadena resultante, no se produce ninguna excepción. Escribiría esa prueba usando lo anteriorassertDoesNotThrow
o el/*comment*/{code}
bloque. Algo comoTambién le animo a que parametrice esta prueba al
input
usarTheories
oParameterized
para que pueda reutilizar esta prueba más fácilmente para otras entradas. Alternativamente, si quieres ir exótico, puedes optar por una herramienta de generación de pruebas (y esto ). TestNG tiene mejor soporte para pruebas parametrizadas.Lo que me parece particularmente desagradable es la recomendación de usar
@Test(expectedException=IllegalArgumentException.class)
, esta excepción es peligrosamente amplia . Si su código cambia de manera tal que el componente bajo el constructor de la prueba tieneif(constructorArgument <= 0) throw IllegalArgumentException()
, y su prueba estaba suministrando 0 para ese argumento porque era conveniente, y esto es muy común, porque generar buenos datos de prueba es un problema sorprendentemente difícil, entonces su prueba será de color verde aunque no pruebe nada. Tal prueba es peor que inútil.fuente
Assert.assertThrows
para verificar que algunos códigos arrojen una excepción.Si tiene la mala suerte de atrapar todos los errores en su código. Puedes hacer estupidamente
fuente
Exception ex
debe ser= null;
antes de que pueda probarlo.JUnit5 agrega el método ClaimAll () para este propósito exacto.
fuente: JUnit 5 API
fuente
Aunque esta publicación tiene 6 años, sin embargo, mucho ha cambiado en el mundo Junit. Con Junit5, ahora puedes usar
Ex:
Espero que ayude a las personas que usan una versión más reciente de Junit5
fuente
Awaitility
'suntilAsserted(ThrowingRunnable assertion)
. El sistema bajo prueba actualmente está lanzando una excepción específica en el ThrowingRunnable que proporciono, pero quiero darle algo de tiempo hasta que deje de hacerlo. Sin embargo, si arrojaría una excepción diferente, me gustaría que la prueba fallara al instante.Si desea probar si su objetivo de prueba consume la excepción. Simplemente deje la prueba como (simulacro de colaborador usando jMock2):
La prueba pasaría si su objetivo consume la excepción lanzada, de lo contrario, la prueba fallaría.
Si desea probar su lógica de consumo de excepción, las cosas se vuelven más complejas. Sugiero delegar el consumo a un colaborador que podría ser burlado. Por lo tanto, la prueba podría ser:
Pero a veces está sobrediseñado si solo desea iniciar sesión. En este caso, este artículo ( http://java.dzone.com/articles/monitoring-declarative-transac , http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there -an-easy-way / ) puede ayudar si insiste en tdd en este caso.
fuente
Utilice afirmar nulo (...)
fuente
assertNull
tampoco se ejecuta. Sin embargo, el lector rápido tiene la impresión de que se hace una afirmación que realmente verifica el caso de no lanzar. En otras palabras: si se alcanza el bloque catch, la excepción siempre es no nula; por lo tanto, se puede reemplazar por un simplefail
.assertNull(e)
informará que la prueba falló, como se indicóe
no puede estarnull
en elcatch
bloque ... Mike, esto es simplemente una programación extraña: - /. .. sí, al menos úsalofail()
como dice AndreasPuede esperar que no se genere una excepción al crear una regla.
fuente
Puede que esta no sea la mejor manera, pero definitivamente se asegura de que no se genere una excepción desde el bloque de código que se está probando.
fuente
Puede hacerlo utilizando una @Rule y luego llamar al método reportMissingExceptionWithMessage como se muestra a continuación: Este es el código Scala.
fuente
private val
? ¿Que idioma es este? Claramente no Java; p Y, por favor, no proporcione código como captura de pantalla, no es bienvenido.Lo siguiente falla la prueba para todas las excepciones, marcadas o no marcadas:
fuente
Puede crear cualquier tipo de sus propias aserciones basadas en aserciones de junit:
Y prueba:
En términos generales, existe la posibilidad de fallar instantáneamente ("bla bla bla") la prueba en cualquier escenario, en cualquier lugar donde tenga sentido. Por ejemplo, úselo en un bloque try / catch para fallar si se arroja algo en el caso de prueba:
Esta es la muestra del método que probamos, suponiendo que tengamos un método que no debe fallar en circunstancias específicas, pero puede fallar:
El método anterior es una muestra simple. Pero esto funciona para situaciones complejas, donde el fracaso no es tan obvio. Están las importaciones:
fuente