java - unitaria - Prueba JUnit-análisis de excepciones esperadas
pruebas unitarias (11)
Solución Java 8
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.
}
Úselo de la siguiente manera:
@Test
public void testThrows()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
throw new RuntimeException( "fail!" );
} );
assert e.getMessage().equals( "fail!" );
}
Además, si desea leer algunas razones por las que no debería querer verificar el mensaje de su excepción, consulte esto: https://softwareengineering.stackexchange.com/a/278958/41811
Esta pregunta ya tiene una respuesta aquí:
En JUnit, actualmente estoy usando la anotación para esperar una excepción en mis pruebas.
¿Hay alguna forma de analizar esta excepción? Por ejemplo, espero una CriticalServerException
, pero también quiero verificar el contenido del método getMessage
.
Mire fluent-exception-rule , "combina la regla de Junit ExpectedException y las aserciones de AssertJ conveniencia".
import pl.wkr.fluentrule.api.FluentExpectedException;
...
@Rule
public FluentExpectedException thrown = FluentExpectedException.none();
@Test
public void testDoSomethingCritical() {
thrown.expect(CriticalServerException.class).hasMessage("Expected Message").hasNoCause();
obj.doSomethingCritical();
}
No creo que haya una forma de hacerlo usando la anotación. Es posible que deba retroceder para intentar capturar el camino donde en el bloque catch puede verificar el mensaje
No estoy seguro de si deberías. Usar un bloque try-catch para verificar el mensaje de error es tan junit3ish . Tenemos esta genial función ahora que puedes escribir @Test(expected=CriticalServerException.class)
y quieres volver atrás y usar try-catch nuevamente para buscar una excepción que esperas, solo para verificar el mensaje de error.
OMI debe permanecer para la @Test(expected=CriticalServerException.class)
e ignorar el mensaje de error. Revisar el mensaje de error, que se puede cambiar mucho ya que es una cadena más "legible por humanos" y no un valor técnico, también puede ser complicado. Está forzando a la excepción a tener un mensaje de error específico, pero es posible que no sepa quién generó la excepción y qué mensaje de error eligió.
En general, desea probar si el método arroja la excepción o no, y no cómo se ve el mensaje de error real. Si el mensaje de error es realmente tan importante, tal vez @Test(expected=...)
considerar usar una subclase de la excepción que lanza y verificarla en @Test(expected=...)
.
Si desea comparar el mensaje junto con el tipo de excepción, puede probar a continuación el fragmento de código.
@Rule
public ExpectedException expectedException = ExpectedException.none();
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Parameter is not valid"); //check string contains
expectedException.expectMessage(CoreMatchers.equalTo("Parameter is not valid")); //check string equals
Nota: Esto funcionará para junit 4.9 en adelante.
Si tiene JUnit 4.7 o superior, intente ExpectedException
Hay un ejemplo en esta pregunta , que se copia a continuación:
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testRodneCisloRok(){
exception.expect(IllegalArgumentException.class);
exception.expectMessage("error1");
new RodneCislo("891415",dopocitej("891415"));
}
Usar catch-exception :
catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
Utilice MethodRule como solución común, si tiene muchos casos de prueba para probar
public class ExceptionRule implements MethodRule {
@Override
public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
Assert.fail();
} catch (CriticalServerException e) {
//Analyze the exception here
}
}
};
}
}
Luego usa la regla para tu clase de prueba:
@Rule public ExceptionRule rule = new ExceptionRule();
try
{
// your code
fail("Didn''t throw expected exception");
}
catch(CriticalServerException e)
{
assertEquals("Expected message", e.getMessage());
}
try {
// test code invacation
fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
try{
//your code expecting to throw an exception
fail("Failed to assert :No exception thrown");
} catch(CriticalServerException ex){
assertNotNull("Failed to assert", ex.getMessage())
assertEquals("Failed to assert", "Expected Message", ex.getMessage());
}