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...)
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 NPE
s, mais commun avec IOException
s et SQLException
s.
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.
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.
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.
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