Dans JUnit, j'utilise actuellement l'annotation pour s'attendre à une exception dans mes tests.
Existe-t-il un moyen d’analyser cette exception? Par exemple, j'attends une CriticalServerException
, mais je souhaite également vérifier le contenu de la méthode getMessage
.
Si vous avez JUnit 4.7 ou supérieur, essayez ExpectedException
Il y a un exemple dans cette question , qui est copié ci-dessous:
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testRodneCisloRok(){
exception.expect(IllegalArgumentException.class);
exception.expectMessage("error1");
new RodneCislo("891415",dopocitej("891415"));
}
Je ne sais pas si tu devrais. Utiliser un bloc try-catch pour vérifier le message d'erreur est donc/ junit3ish . Nous avons cette fonctionnalité intéressante maintenant que vous pouvez écrire @Test(expected=CriticalServerException.class)
et que vous voulez revenir en arrière et utiliser try-catch à nouveau pour récupérer une exception que vous attendez, juste pour vérifier le message d'erreur?
OMI, vous devriez rester pour l'annotation @Test(expected=CriticalServerException.class)
et ignorer le message d'erreur. Vérifier le message d'erreur, qui peut être beaucoup modifié car il s'agit d'une chaîne plus "lisible par l'homme" et non d'une valeur technique, peut également être délicat. Vous forcez l’exception à avoir un message d’erreur spécifique, mais vous pouvez ne pas savoir qui a généré l’exception et quel message d’erreur il a choisi.
En général, vous voulez vérifier si la méthode lève l'exception ou non, et non à quoi ressemble le message d'erreur. Si le message d'erreur est vraiment si important, vous devriez peut-être envisager d'utiliser une sous-classe de l'exception générée et l'exécuter dans @Test(expected=...)
.
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());
}
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"));
}
Utilisez MethodRule comme solution commune, si vous avez plusieurs scénarios de test à tester.
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
}
}
};
}
}
Puis utilisez la règle dans votre classe de test:
@Rule public ExceptionRule rule = new ExceptionRule();
Je ne pense pas qu'il y ait moyen de le faire en utilisant une annotation. Vous devrez peut-être vous rabattre sur le chemin try-catch où, dans le bloc catch, vous pouvez vérifier le message.
Utilisez catch-exception :
catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
Regardez fluent-exception-rule , il "combine la règle Junit ExpectedException et la commodité des assertions d'AssertJ".
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();
}
Voici une fonction utilitaire que j'ai écrite:
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.
}
Utilisez-le comme suit:
@Test
public void testThrows()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
throw new RuntimeException( "fail!" );
} );
assert e.getMessage().equals( "fail!" );
}
De plus, si vous souhaitez lire certaines raisons pour lesquelles vous devriez pas vouloir vérifier le message de votre exception, consultez ceci: https://softwareengineering.stackexchange.com/a/ 278958/41811
Si vous souhaitez comparer le message avec le type d'exception, vous pouvez essayer le code ci-dessous.
@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
Note: Cela fonctionnera à partir du 4 juin.