Introduction à JUnitParams

Introduction à JUnitParams

1. Vue d'ensemble

Dans cet article, nous allons explorer la bibliothèqueJUnitParams et ses utilisations. En termes simples, cette bibliothèque permet de paramétrer facilement les méthodes de test dans les testsJUnit.

Il existe des situations où la seule chose qui change entre plusieurs tests sont les paramètres. JUnit lui-même a un support de paramétrage, etJUnitParams améliore considérablement cette fonctionnalité.

2. Dépendance Maven

Pour utiliserJUnitParams dans notre projet, nous devons l'ajouter à nospom.xml:


    pl.pragmatists
    JUnitParams
    1.1.0

La dernière version de la bibliothèque peut être trouvéehere.

3. Scénario de test

Créons une classe qui effectue l’addition sûre de deux entiers. Cela devrait renvoyerInteger.MAX_VALUE s'il déborde, etInteger.MIN_VALUE s'il sous-déborde:

public class SafeAdditionUtil {

    public int safeAdd(int a, int b) {
        long result = ((long) a) + b;
        if (result > Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        } else if (result < Integer.MIN_VALUE) {
            return Integer.MIN_VALUE;
        }
        return (int) result;
    }
}

4. Construire une méthode de test simple

Nous devrons tester la mise en œuvre de la méthode pour différentes combinaisons de valeurs d'entrée, afin de nous assurer que la mise en œuvre est vraie pour tous les scénarios possibles. JUnitParams fournit plusieurs méthodes pour réaliser la création de test paramétrée.

Prenons l’approche de base avec un minimum de codage et voyons comment cela se fait. Après cela, nous pouvons voir quelles sont les autres façons possibles d'implémenter les scénarios de test à l'aide de JUnitParams sont:

@RunWith(JUnitParamsRunner.class)
public class SafeAdditionUtilTest {

    private SafeAdditionUtil serviceUnderTest
      = new SafeAdditionUtil();

    @Test
    @Parameters({
      "1, 2, 3",
      "-10, 30, 20",
      "15, -5, 10",
      "-5, -10, -15" })
    public void whenWithAnnotationProvidedParams_thenSafeAdd(
      int a, int b, int expectedValue) {

        assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
    }

}

Voyons maintenant en quoi cette classe de test diffère d'une classe de testJUnit normale.

La première chose que nous remarquons est quethere is adifferent test runner dans l'annotation de classe -JUnitParamsRunner.

En passant à la méthode de test, nous voyons que la méthode de test est annotée avec l'annotation@Parameters avec un tableau de paramètres d'entrée. Il indique différents scénarios de test qui seront utilisés pour tester notre méthode de service.

Si nous exécutons le test avec Maven, nous verrons quewe are running four test cases and not a single one. La sortie serait semblable à la suivante:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.example.junitparams.SafeAdditionUtilTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.068 sec
  - in com.example.junitparams.SafeAdditionUtilTest

Results :

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

5. Différents types de paramétrage des méthodes de test

Fournir des paramètres de test directement dans l'annotation n'est certainement pas le moyen le plus lisible si de nombreux scénarios doivent être testés. JUnitParams propose un ensemble d'approches différentes que nous pouvons utiliser pour créer les tests paramétrés:

  • Directement dans l'annotation@Parameters (utilisée dans l'exemple ci-dessus)

  • Utilisation d'une méthode de test nommée définie dans l'annotation

  • Utilisation d'une méthode mappée par nom de méthode de test

  • Une classe de test nommée définie dans l'annotation

  • Utiliser un fichier CSV

Explorons les approches une par une.

5.1. Directement dans l'annotation@Parameters

Nous avons déjà utilisé cette approche dans l'exemple que nous avons essayé. Nous devons garder à l’esprit que nous devrions fournir un tableau de chaînes de paramètres. Dans la chaîne de paramètres, chaque paramètre est séparé par une virgule.

Par exemple, le tableau serait sous la forme de\{ “1, 2, 3”, “-10, 30, 20”} et un ensemble de paramètres est représenté par“1, 2, 3”.

La limitation de cette approche est que nous ne pouvons fournir que des primitives et desStrings comme paramètres de test. Il n'est pas possible de soumettre des objets en tant que paramètres de méthode de test.

5.2. Méthode de paramètre

Nous pouvons fournir les paramètres de la méthode de test en utilisant une autre méthode de la classe. Voyons d'abord un exemple:

@Test
@Parameters(method = "parametersToTestAdd")
public void whenWithNamedMethod_thenSafeAdd(
  int a, int b, int expectedValue) {

    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}

private Object[] parametersToTestAdd() {
    return new Object[] {
        new Object[] { 1, 2, 3 },
        new Object[] { -10, 30, 20 },
        new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE },
        new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE }
    };
}

La méthode de test est annotée concernant la méthodeparametersToAdd(), et elle récupère les paramètres en exécutant la méthode référencée.

La spécification de la méthode du fournisseur doit renvoyer un tableau deObjects en conséquence. Si une méthode portant le nom donné n'est pas disponible, le scénario de test échoue avec l'erreur suivante:

java.lang.RuntimeException: Could not find method: bogusMethodName so no params were used.

5.3. Méthode mappée par nom de méthode de test

Si nous ne spécifions rien dans l'annotation@Parameters,JUnitParams essaie de charger une méthode de fournisseur de données de test basée sur le nom de la méthode de test. Le nom de la méthode est construit comme“parametersFor”+ <test method name>:

@Test
@Parameters
public void whenWithnoParam_thenLoadByNameSafeAdd(
  int a, int b, int expectedValue) {

    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}

private Object[] parametersForWhenWithnoParam_thenLoadByNameSafe() {
    return new Object[] {
        new Object[] { 1, 2, 3 },
        new Object[] { -10, 30, 20 },
        new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE },
        new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE }
    };
}

Dans l'exemple ci-dessus, le nom de la méthode de test estwhenWithnoParam_shouldLoadByNameAbdSafeAdd().

Par conséquent, lorsque la méthode de test est exécutée, elle recherche une méthode de fournisseur de données avec le nomparametersForWhenWithnoParam_shouldLoadByNameAbdSafeAdd().

Comme cette méthode existe, il chargera les données et exécutera le test. If there is no such method matching the required name, the test fails comme dans l'exemple ci-dessus.

5.4. Classe de test nommée définie dans l'annotation

De la même manière que nous avons fait référence à une méthode de fournisseur de données dans un exemple précédent, nous pouvons faire référence à une classe séparée pour fournir les données de notre test:

@Test
@Parameters(source = TestDataProvider.class)
public void whenWithNamedClass_thenSafeAdd(
  int a, int b, int expectedValue) {

    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}
public class TestDataProvider {

    public static Object[] provideBasicData() {
        return new Object[] {
            new Object[] { 1, 2, 3 },
            new Object[] { -10, 30, 20 },
            new Object[] { 15, -5, 10 },
            new Object[] { -5, -10, -15 }
        };
    }

    public static Object[] provideEdgeCaseData() {
        return new Object[] {
            new Object[] {
              Integer.MAX_VALUE, 2, Integer.MAX_VALUE },
            new Object[] {
              Integer.MIN_VALUE, -2, Integer.MIN_VALUE },
        };
    }
}

Nous pouvons avoir n'importe quel nombre de fournisseurs de données de test dans une classe étant donné que le nom de la méthode commence par «fournit». Si c'est le cas, l'exécuteur choisit ces méthodes et renvoie les données.

Si aucune méthode de classe ne satisfait cette exigence, même si ces méthodes renvoient un tableau deObjects, ces méthodes seront ignorées.

5.5. Utilisation d'un fichier CSV

Nous pouvons utiliser un fichier CSV externe pour charger les données de test. Cela est utile si le nombre de cas de test possibles est assez important ou si les cas de test changent fréquemment. Les modifications peuvent être effectuées sans affecter le code de test.

Supposons que nous ayons un fichier CSV avec des paramètres de test commeJunitParamsTestParameters.csv:

1,2,3
-10, 30, 20
15, -5, 10
-5, -10, -15

Voyons maintenant commentthis file can be used to load test parameters dans la méthode de test:

@Test
@FileParameters("src/test/resources/JunitParamsTestParameters.csv")
public void whenWithCsvFile_thenSafeAdd(
  int a, int b, int expectedValue) {

    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}

Une des limites de cette approche est qu’il n’est pas possible de transmettre des objets complexes. Seules les primitives et lesStrings sont valides.

6. Conclusion

Dans ce didacticiel, nous avons examiné comment pouvons-nous utiliser les fonctionnalités deJUnitParams en un mot.

Nous avons également abordé différentes approches proposées par la bibliothèque pour fournir des paramètres de test à nos méthodes de test - bien au-delà de ce que JUnit lui-même peut faire.

Comme toujours, le code source peut être trouvéover on GitHub.