441 votes

Comment tester qu'aucune exception n'est levée ?

Je sais qu'une façon de le faire serait :

@Test
public void foo() {
   try {
      // execute code that you expect not to throw Exceptions.
   } catch(Exception e) {
      fail("Should not have thrown any exception");
   }
}

Existe-t-il un moyen plus propre de procéder ? (Probablement en utilisant la fonction @Rule ?)

14 votes

Un test JUnit est considéré comme ayant échoué s'il lève une exception autre qu'une exception attendue. En général, aucune exception n'est attendue.

2 votes

N'y a-t-il pas une distinction entre échec et erreur dans JUnit ? Le premier signifie que le test a échoué, le second que quelque chose d'inattendu s'est produit.

2 votes

1voto

Hippoom Points 2792

Si vous voulez tester que votre cible de test consomme l'exception. Laissez simplement le test comme (mock collaborator using jMock2) :

@Test
public void consumesAndLogsExceptions() throws Exception {

    context.checking(new Expectations() {
        {
            oneOf(collaborator).doSth();
            will(throwException(new NullPointerException()));
        }
    });

    target.doSth();
 }

Le test passe si votre cible consomme l'exception levée, sinon le test échoue.

Si vous voulez tester votre logique de consommation des exceptions, les choses deviennent plus complexes. Je suggère de déléguer la consommation à un collaborateur qui pourrait être simulé. Par conséquent, le test pourrait être :

@Test
public void consumesAndLogsExceptions() throws Exception {
    Exception e = new NullPointerException();
    context.checking(new Expectations() {
        {
            allowing(collaborator).doSth();
            will(throwException(e));

            oneOf(consumer).consume(e);
        }
    });

    target.doSth();
 }

Mais parfois, il est surdimensionné si vous voulez juste l'enregistrer. Dans ce cas, cet article( http://java.dzone.com/articles/monitoring-declarative-transac , http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/ ) peut aider si vous insistez sur le tdd dans ce cas.

1voto

Michael Rapadas Points 560

Utilisez assertNull(...)

@Test
public void foo() {
    try {
        //execute code that you expect not to throw Exceptions.
    } catch (Exception e){
        assertNull(e);
    }
}

1voto

MLS Points 129

Ce n'est peut-être pas la meilleure solution, mais elle permet de s'assurer que l'exception n'est pas levée à partir du bloc de code qui est testé.

import org.assertj.core.api.Assertions;
import org.junit.Test;

public class AssertionExample {

    @Test
    public void testNoException(){
        assertNoException();
    }    

    private void assertException(){
        Assertions.assertThatThrownBy(this::doNotThrowException).isInstanceOf(Exception.class);
    }

    private void assertNoException(){
        Assertions.assertThatThrownBy(() -> assertException()).isInstanceOf(AssertionError.class);
    }

    private void doNotThrowException(){
        //This method will never throw exception
    }
}

1voto

armagedescu Points 149

Vous pouvez créer n'importe quel type de vos propres assertions basées sur les assertions de junit, car celles-ci sont spécialement conçues pour créer des assertions définies par l'utilisateur et destinées à fonctionner exactement comme celles de junit :

static void assertDoesNotThrow(Executable executable) {
    assertDoesNotThrow(executable, "must not throw");
}
static void assertDoesNotThrow(Executable executable, String message) {
    try {
        executable.execute();
    } catch (Throwable err) {
        fail(message);
    }
}

Testons maintenant le soi-disant scénario méthodeMustNotThrow et de consigner tous les échecs dans un style junit :

//test and log with default and custom messages
//the following will succeed
assertDoesNotThrow(()->methodMustNotThrow(1));
assertDoesNotThrow(()->methodMustNotThrow(1), "custom facepalm");
//the following will fail
assertDoesNotThrow(()->methodMustNotThrow(2));
assertDoesNotThrow(()-> {throw new Exception("Hello world");}, "message");
//See implementation of methodMustNotThrow below

D'une manière générale, il est possible de faire échouer instantanément n'importe quel test dans n'importe quel scénario, à n'importe quel endroit où cela a un sens, en appelant fail(someMessage) qui est conçu exactement dans ce but. Par exemple, utilisez-le dans un bloc try/catch pour échouer si quelque chose est lancé dans le scénario de test :

try{methodMustNotThrow(1);}catch(Throwable e){fail("must not throw");}
try{methodMustNotThrow(1);}catch(Throwable e){Assertions.fail("must not throw");}

C'est l'échantillon de la méthode que nous testons, en supposant que nous ayons une telle méthode qui ne doit pas échouer dans des circonstances spécifiques, mais elle peut échouer :

void methodMustNotThrow(int x) throws Exception {
    if (x == 1) return;
    throw new Exception();
}

La méthode ci-dessus est un exemple simple. Mais cela fonctionne pour des situations complexes, où l'échec n'est pas si évident. Il y a les importations :

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import static org.junit.jupiter.api.Assertions.*;

1voto

Yair Landmann Points 41

J'ai été confronté à la même situation, j'avais besoin de vérifier que l'exception est levée quand elle le doit, et seulement quand elle le doit. J'ai fini par utiliser le gestionnaire d'exception à mon avantage avec le code suivant :

    try {
        functionThatMightThrowException()
    }catch (Exception e){
        Assert.fail("should not throw exception");
    }
    RestOfAssertions();

Le principal avantage pour moi est qu'il est assez simple et qu'il est très facile de vérifier l'autre sens du "si et seulement si" dans cette même structure.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X