web-dev-qa-db-fra.com

Test JUnit - analyse des exceptions attendues

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.

41
Farid

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"));
}
68
Filippo Vitale

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=...).

21
Progman
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());
}
12
Jigar Joshi
try
{
    // your code

    fail("Didn't throw expected exception");
}
catch(CriticalServerException e)
{
    assertEquals("Expected message", e.getMessage());
}
2
Brian
try {
    // test code invacation
    fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
    assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
2
Alex

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(); 
2

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.

1
Ankit Bansal

Utilisez catch-exception :

catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
0
rwitzel

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();
}
0
Marcin

Solution Java 8

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.
}

( extrait de mon blog )

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

0
Mike Nakis

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.

0
Meet