web-dev-qa-db-fra.com

comment gérer les exceptions dans junit

J'ai écrit quelques cas de test pour tester une méthode. Mais certaines méthodes lèvent une exception. Suis-je en train de le faire correctement?

private void testNumber(String Word, int number) {
    try {
        assertEquals(Word,  service.convert(number));
    } catch (OutOfRangeNumberException e) {
        Assert.fail("Test failed : " + e.getMessage());
    }
}

@Test
public final void testZero() {
    testNumber("zero", 0);
}

Si je passe -45, Il échouera avec OutOfRangeException mais je ne suis pas en mesure de tester une exception spécifique comme @Test(Expected...)

26
Sammy Pawar

Une exception inattendue est un échec de test, vous n'avez donc ni besoin ni envie de l'attraper.

@Test
public void canConvertStringsToDecimals() {
    String str = "1.234";
    Assert.assertEquals(1.234, service.convert(str), 1.0e-4);
}

Jusqu'à ce que service ne lance pas de IllegalArgumentException parce que str contient un point décimal, ce sera un simple échec de test.

Une exception attendue doit être gérée par l'argument facultatif expected de @Test.

@Test(expected=NullPointerException.class)
public void cannotConvertNulls() {
    service.convert(null);
}

Si le programmeur était paresseux et a jeté Exception, ou s'il avait service return 0.0, le test échouera. Seul un NPE réussira. Notez que les sous-classes de l'exception attendue fonctionnent également. C'est rare pour NPEs, mais commun avec IOExceptions et SQLExceptions.

Dans les rares cas où vous souhaitez tester un message d'exception spécifique, vous utilisez le nouveau ExpectedException JUnit @Rule.

@Rule
public ExpectedException thrown= ExpectedException.none();
@Test
public void messageIncludesErrantTemperature() {
    thrown.expect(IllegalArgumentException.class);
    thrown.expectMessage("-400"); // Tests that the message contains -400.
    temperatureGauge.setTemperature(-400);
}

Maintenant, à moins que setTemperature ne lance un IAE et que le message contienne la température que l'utilisateur essayait de définir, le test échoue. Cette règle peut être utilisée de manière plus sophistiquée.


Votre exemple peut être mieux géré par:

private void testNumber(String Word, int number)
        throws OutOfRangeNumberException {
    assertEquals(Word,  service.convert(number));
}

@Test
public final void testZero()
        throws OutOfRangeNumberException {
    testNumber("zero", 0);
}

Vous pouvez inline testNumber; maintenant, cela n'aide pas beaucoup. Vous pouvez transformer cela en une classe de test paramétrée.

48
Eric Jablow

Supprimez le bloc try-catch et ajoutez throws Exception à votre méthode de test, comme:

@Test
public final void testZero() throws Exception {
    assertEquals("zero",  service.convert(0));
}

JUnit s'attend à ce que les tests qui échouent lèvent des exceptions, votre capture les empêche simplement de JUnit de pouvoir les signaler correctement. De cette façon, la propriété attendue sur l'annotation @Test fonctionnera également.

23
Nathan Hughes

Vous n'avez pas besoin d'attraper l'exception pour échouer au test. Laissez-le simplement partir (en déclarant throws) et il échouera quand même.

Un autre cas est lorsque vous vous attendez réellement à l'exception, puis vous mettez échouer à la fin du bloc try.

Par exemple:

@Test
public void testInvalidNumber() {
  try {
      String dummy = service.convert(-1));
      Assert.fail("Fail! Method was expected to throw an exception because negative numbers are not supported.")
  } catch (OutOfRangeException e) {
      // expected
  }
}

Vous pouvez utiliser ce type de test pour vérifier si votre code valide correctement les entrées et gère les entrées non valides avec une exception appropriée.

7
javadeveloper

Plusieurs stratégies s'offrent à vous pour gérer les exceptions attendues dans vos tests. Je pense que les annotations JUnit et l'idiome try/catch ont déjà été mentionnés ci-dessus. Je voudrais attirer l'attention sur l'option Java 8 des expressions Lambda.

Par exemple, donné:

class DummyService {
public void someMethod() {
    throw new RuntimeException("Runtime exception occurred");
}

public void someOtherMethod(boolean b) {
    throw new RuntimeException("Runtime exception occurred",
            new IllegalStateException("Illegal state"));
}

}

Tu peux le faire:

@Test
public void verifiesCauseType() {
    // lambda expression
    assertThrown(() -> new DummyService().someOtherMethod(true))
            // assertions
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Runtime exception occurred")
            .hasCauseInstanceOf(IllegalStateException.class);
}

Jetez un œil à ce blog qui couvre la plupart des options avec des exemples.

http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html

Et celui-ci explique plus en détail l'option Java 8 Lambda:

http://blog.codeleak.pl/2014/07/junit-testing-exception-with-Java-8-and-lambda-expressions.html

3
raghera