Assertions personnalisées avec AssertJ

Assertions personnalisées avec AssertJ

 

1. Vue d'ensemble

Dans ce didacticiel, nous allons vous expliquer comment créer des assertionsAssertJ personnalisées; les bases d'AssertJcan be found here.

En termes simples, les assertions personnalisées permettent de créer des assertions spécifiques à nos propres classes, ce qui permet à nos tests de mieux refléter le modèle de domaine.

2. Classe sous test

Les cas de test de ce didacticiel seront construits autour de la classePerson:

public class Person {
    private String fullName;
    private int age;
    private List nicknames;

    public Person(String fullName, int age) {
        this.fullName = fullName;
        this.age = age;
        this.nicknames = new ArrayList<>();
    }

    public void addNickname(String nickname) {
        nicknames.add(nickname);
    }

    // getters
}

3. Classe d'assertion personnalisée

L'écriture d'une classe d'assertion AssertJ personnalisée est assez simple. All we need to do is to declare a class that extends AbstractAssert, add a required constructor, and provide custom assertion methods.

La classe d'assertion doit étendre la classeAbstractAssert pour nous donner accès aux méthodes d'assertion essentielles de l'API, telles queisNotNull etisEqualTo.

Voici le squelette d'une classe d'assertion personnalisée pourPerson:

public class PersonAssert extends AbstractAssert {

    public PersonAssert(Person actual) {
        super(actual, PersonAssert.class);
    }

    // assertion methods described later
}

Nous devons spécifier deux arguments de type lors de l'extension de la classeAbstractAssert: le premier est la classe d'assertion personnalisée elle-même, qui est requise pour le chaînage de méthodes, et le second est la classe testée.

Pour fournir un point d'entrée à notre classe d'assertion, nous pouvons définir une méthode statique pouvant être utilisée pour démarrer une chaîne d'assertions:

public static PersonAssert assertThat(Person actual) {
    return new PersonAssert(actual);
}

Ensuite, nous allons passer en revue plusieurs assertions personnalisées incluses dans la classePersonAssert.

La première méthode vérifie que le nom complet d'unPerson correspond à un argumentString:

public PersonAssert hasFullName(String fullName) {
    isNotNull();
    if (!actual.getFullName().equals(fullName)) {
        failWithMessage("Expected person to have full name %s but was %s",
          fullName, actual.getFullName());
    }
    return this;
}

La méthode suivante teste si unPerson est un adulte en fonction de sesage:

public PersonAssert isAdult() {
    isNotNull();
    if (actual.getAge() < 18) {
        failWithMessage("Expected person to be adult");
    }
    return this;
}

Les dernières vérifications de l'existence d'unnickname:

public PersonAssert hasNickName(String nickName) {
    isNotNull();
    if (!actual.getNickNames().contains(nickName)) {
        failWithMessage("Expected person to have nickname %s",
          nickName);
    }
    return this;
}

Lorsque vous avez plus d'une classe d'assertion personnalisée, nous pouvons envelopper toutes les méthodesassertThat dans une classe, en fournissant une méthode de fabrique statique pour chacune des classes d'assertion:

public class Assertions {
    public static PersonAssert assertThat(Person actual) {
        return new PersonAssert(actual);
    }

    // static factory methods of other assertion classes
}

La classeAssertions illustrée ci-dessus est un point d'entrée pratique pour toutes les classes d'assertions personnalisées.

Les méthodes statiques de cette classe ont le même nom et sont différenciées les unes des autres par leur type de paramètre.

4. En action

Les cas de test suivants illustrent les méthodes d'assertion personnalisées que nous avons créées dans la section précédente. Notez que la méthodeassertThat est importée de notre classe personnaliséeAssertions, et non de l'API AssertJ principale.

Voici comment la méthodehasFullName peut être utilisée:

@Test
public void whenPersonNameMatches_thenCorrect() {
    Person person = new Person("John Doe", 20);
    assertThat(person)
      .hasFullName("John Doe");
}

Ceci est un cas de test négatif illustrant la méthodeisAdult:

@Test
public void whenPersonAgeLessThanEighteen_thenNotAdult() {
    Person person = new Person("Jane Roe", 16);

    // assertion fails
    assertThat(person).isAdult();
}

et un autre test démontrant la méthodehasNickname:

@Test
public void whenPersonDoesNotHaveAMatchingNickname_thenIncorrect() {
    Person person = new Person("John Doe", 20);
    person.addNickname("Nick");

    // assertion will fail
    assertThat(person)
      .hasNickname("John");
}

5. Générateur d'assertions

L'écriture de classes d'assertions personnalisées correspondant au modèle d'objet ouvre la voie à des cas de test très lisibles.

However, if we have a lot of classes, it would be painful to manually create custom assertion classes for all of them. C’est là que le générateur d’assertions AssertJ entre en jeu.

Pour utiliser le générateur d'assertions avec Maven, nous devons ajouter un plugin au fichierpom.xml:


    org.assertj
    assertj-assertions-generator-maven-plugin
    2.1.0
    
        
            com.example.testing.assertj.custom.Person
        
    

La dernière version desassertj-assertions-generator-maven-plugin peut être trouvéehere.

L'élémentclasses dans le plugin ci-dessus marque les classes pour lesquelles nous voulons générer des assertions. Veuillez consulterthis post pour d'autres configurations du plugin.

The AssertJ assertions generator creates assertions for each public property of the target class. Le nom spécifique de chaque méthode d'assertion dépend du type du champ ou de la propriété. Pour une description complète du générateur d'assertions, consultezthis reference.

Exécutez la commande Maven suivante dans le répertoire de base du projet:

mvn assertj:generate-assertions

Nous devrions voir les classes d'assertions générées dans le dossiertarget/generated-test-sources/assertj-assertions. For example, la classe de point d'entrée générée pour les assertions générées ressemble à ceci:

// generated comments are stripped off for brevity

package com.example.testing.assertj.custom;

@javax.annotation.Generated(value="assertj-assertions-generator")
public class Assertions {

    @org.assertj.core.util.CheckReturnValue
    public static com.example.testing.assertj.custom.PersonAssert
      assertThat(com.example.testing.assertj.custom.Person actual) {
        return new com.example.testing.assertj.custom.PersonAssert(actual);
    }

    protected Assertions() {
        // empty
    }
}

Maintenant, nous pouvons copier les fichiers source générés dans le répertoire de test, puis ajouter des méthodes d'assertion personnalisées pour répondre à nos exigences en matière de test.

Une chose importante à noter est que le code généré n'est pas garanti d'être entièrement correct. À ce stade, le générateur n'est pas un produit fini et la communauté y travaille.

Par conséquent, nous devrions utiliser le générateur comme outil de support pour nous faciliter la vie au lieu de le prendre pour acquis.

6. Conclusion

Dans ce didacticiel, nous avons montré comment créer des assertions personnalisées pour créer un code de test lisible avec la bibliothèque AssertJ, à la fois manuellement et automatiquement.

Si nous ne testons qu'un petit nombre de classes, la solution manuelle suffit. sinon, le générateur devrait être utilisé.

Et, comme toujours, l'implémentation de tous les exemples et extraits de code peut être trouvéeover on GitHub.