web-dev-qa-db-fra.com

Confusion JUnit: utiliser 'étend TestCase' ou '@Test'?

J'ai trouvé l'utilisation de JUnit (ou du moins la documentation) 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 (style JUnit 3): créez une classe qui étend TestCase et démarrez des méthodes de test avec Word test. Lors de l'exécution de la classe en tant que JUnit Test (dans Eclipse), toutes les méthodes commençant par Word 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 (style JUnit 4): créez une classe 'normale' et ajoutez une annotation @Test À la méthode. Notez que vous ne devez PAS 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 de stackoverflow :

Maintenant, mes questions:

  1. Quelle est l'approche préférée ou quand utiliseriez-vous l'une au lieu de l'autre?
  2. L'approche B permet de tester les exceptions en développant l'annotation @Test comme dans @Test(expected = ArithmeticException.class). Mais comment testez-vous les exceptions lorsque vous utilisez l'approche A?
  3. Lorsque vous utilisez l'approche A, vous pouvez regrouper un certain nombre de classes de test dans une suite de tests, comme suit:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    Mais ceci ne peut pas être utilisé avec l'approche B (puisque chaque classe de test devrait sous-classer 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

146
Rabarberski

La distinction est plutôt facile:

  • l'extension de TestCase correspond à la manière dont les tests unitaires ont été écrits dans JUnit 3 (bien sûr, il est toujours pris en charge dans JUnit 4)
  • en utilisant le @Test L'annotation est la voie introduite par JUnit 4

En règle générale, vous devez choisir le chemin des annotations, sauf si la compatibilité avec JUnit 3 (et/ou une version de Java antérieure à Java 5) est requise.). plusieurs avantages:

Pour tester les exceptions attendues dans un JUnit 3 TestCase, vous devez expliciter le texte.

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
  }
}
111
Joachim Sauer

J'ai une préférence pour JUnit 4 (approche d'annotation) car je le 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 celui-ci:

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 */
}
24
Grimmy

Il y a une partie de votre question qui reste sans réponse: "Quelle est la bonne façon de grouper les tests pour l'approche B?"

La réponse officielle est que vous annotez une classe avec un @RunWith (Suite.class), puis utilisez l'annotation @ Suite.SuiteClasses pour répertorier les classes. C’est comme cela que les développeurs JUnit le font (listant manuellement chaque classe d’une suite). À bien des égards, cette approche constitue une amélioration, car il est simple et intuitif d’ajouter des comportements avant et après la suite (il suffit d’ajouter une méthode @BeforeClass et @AfterClass à la classe annotée avec @RunWith, bien mieux que l’ancien TestFixture. ).

Cependant, il y a un pas en arrière dans la mesure où les annotations ne vous permettent pas de créer dynamiquement la liste de classes et que le contournement de ce problème devient un peu moche. Vous devez sous-classer la classe Suite, créer dynamiquement le tableau de classes de la sous-classe et le transmettre au constructeur de Suite, mais il s'agit d'une solution incomplète dans la mesure où d'autres sous-classes de Suite (telles que les catégories) ne fonctionnent pas avec ce dernier. ne prend pas en charge la collection de classes de test dynamique.

15
Yishai

Vous devriez utiliser JUnit 4. C'est mieux.

De nombreux frameworks ont commencé à déprécier le support de JUnit 3.8.

Ceci est tiré de la documentation de référence de Spring 3.0:

[Avertissement] L'ancienne hiérarchie de classes JUnit 3.8 est obsolète

En général, vous devriez toujours essayer d'utiliser la dernière version stable d'un framework lorsque vous démarrez quelque chose de nouveau.

4
Espen
  1. L’approche "préférée" consisterait à utiliser les annotations introduites depuis Junit 4. Elles facilitent beaucoup de choses (voir votre deuxième question)

  2. Vous pouvez utiliser un simple bloc try/catch pour cela:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
1
black666