JUnit confusion: utilisez 'extends TestCase' ou '@Test'?
J'ai trouvé l'utilisation correcte (ou du moins la documentation) de JUnit très déroutante. Cette question sert à la fois de référence future et de vraie question.
Si j'ai bien compris, il existe deux approches principales pour créer et exécuter un test JUnit:
Approche A (JUnit 3-style): créez une classe qui étend TestCase et démarrez les méthodes de test avec le mot test
. Lors de l'exécution de la classe en tant que test JUnit (dans Eclipse), toutes les méthodes démarrent avec le mot test
sont automatiquement exécutées.
import junit.framework.TestCase;
public class DummyTestA extends TestCase {
public void testSum() {
int a = 5;
int b = 10;
int result = a + b;
assertEquals(15, result);
}
}
Approche B (JUnit 4-style): crée une classe 'normale' et ajoute une annotation @Test
à la méthode. Notez que vous n'avez PAS besoin de démarrer la méthode avec le mot test
.
import org.junit.*;
import static org.junit.Assert.*;
public class DummyTestB {
@Test
public void Sum() {
int a = 5;
int b = 10;
int result = a + b;
assertEquals(15, result);
}
}
Mélanger les deux ne semble pas être une bonne idée, voir par exemple cette question stackoverflow:
Maintenant, mes questions:
- Quelle est l'approche préférée, ou quand utiliseriez-vous une au lieu de la les autres?
- L'approche B permet de tester les exceptions en étendant l'annotation @Test comme dans
@Test(expected = ArithmeticException.class)
. Mais comment testez-vous les exceptions lors de l'utilisation de l'approche A? -
Lorsque vous utilisez l'approche A, vous pouvez regrouper un certain nombre de classes de test dans une suite de tests comme ceci:
TestSuite suite = new TestSuite("All tests");
suite.addTestSuite(DummyTestA.class);
suite.addTestSuite(DummyTestAbis.class);
Mais cela ne peut pas être utilisé avec l'approche B (puisque chaque classe de test devrait sous-classe TestCase). Quelle est la bonne façon de regrouper les tests pour l'approche B?
Edit: J'ai ajouté les versions JUnit aux deux approches
5 answers
La distinction est plutôt facile:
- l'extension de
TestCase
est la façon dont les tests unitaires ont été écrits dans JUnit 3 (bien sûr, il est toujours pris en charge dans JUnit 4) - l'utilisation de l'annotation
@Test
est la voie introduite par JUnit 4
Généralement, vous devez choisir le chemin d'annotation, sauf si la compatibilité avec JUnit 3 (et/ou une version Java antérieure à Java 5) est nécessaire. La nouvelle méthode présente plusieurs avantages:
- Le
@Test
annotaton est plus explicite et est plus facile à supporter dans les outils (par exemple, il est facile de rechercher tous les tests de cette façon) - Plusieurs méthodes peuvent être annotées avec
@Before
/@BeforeClass
et@After
/@AfterClass
en offrant plus de flexibilité - Support pour
@Rule
annotations sur des choses commeExpectedException
- Prise en charge de la
@Ignored
annotation - Prise en charge des coureurs de test alternatifs utilisant
@RunWith
À testez les exceptions attendues dans un JUnit 3 TestCase
vous devrez rendre le texte explicite.
public void testMyException() {
try {
objectUnderTest.myMethod(EVIL_ARGUMENT);
fail("myMethod did not throw an Exception!");
} catch (MyException e) {
// ok!
// check for properties of exception here, if desired
}
}
JUnit 5 a introduit un autre changement d'API, mais utilise toujours des annotations. La nouvelle annotation @Test
est org.junit.jupiter.api.Test
(le" vieux " JUnit 4 était org.junit.Test
), mais il fonctionne à peu près de la même manière que le JUnit 4.
J'ai une préférence pour JUnit 4 (approche d'annotation) car je la trouve plus flexible.
Si vous voulez construire une suite de tests dans JUnit 4, vous devez créer une classe regroupant tous les tests comme ceci:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
Test1.class,
Test2.class,
Test3.class,
Test4.class
})public class TestSuite
{
/* empty class */
}
Il y a une partie sans réponse à votre question, et c'est "Quelle est la bonne façon de regrouper les tests pour l'approche B?"
La réponse officielle est que vous annotez une classe avec un @RunWith(Suite.classe), puis utilisez la @ Suite.Annotation SuiteClasses pour lister les classes. C'est ainsi que les développeurs JUnit le font (liste manuelle de chaque classe d'une suite). À bien des égards, cette approche est une amélioration, en ce sens qu'il est trivial et intuitif d'ajouter des comportements avant et après suite (juste ajoutez une méthode @BeforeClass et @AfterClass à la classe annotée avec @RunWith-beaucoup mieux que l'ancien TestFixture).
Cependant, il a un pas en arrière, en ce sens que les annotations ne vous permettent pas de créer dynamiquement la liste des classes, et contourner ce problème devient un peu moche. Vous devez sous-classer la classe Suite et créer dynamiquement le tableau de classes dans la sous-classe et le transmettre au constructeur Suite, mais il s'agit d'une solution incomplète dans cet autre les sous-classes de la suite (telles que les catégories) ne fonctionnent pas avec elle et ne prennent essentiellement pas en charge la collection de classes de test dynamique.
Vous devez utiliser JUnit 4. C'est mieux.
Beaucoup de frameworks ont commencé à déprécier le support JUnit 3.8.
Ceci provient de la documentation de référence Spring 3.0:
[Avertissement] Classe JUnit 3.8 héritée la hiérarchie est obsolète
En général, vous devriez toujours essayer d'utiliser la dernière version stable d'un cadre, lorsque vous commencez quelque chose de nouveau.
-
L'approche "préférée"serait d'utiliser des annotations qui ont été introduites depuis le 4 juin. Ils facilitent beaucoup de choses (voir votre deuxième question)
Vous pouvez utiliser un simple bloc try/catch pour que:
public void testForException() {
try {
Integer.parseInt("just a string");
fail("Exception should have been thrown");
} catch (final Exception e) {
// expected
}
}