Skip to main content

Écrire des tests unitaires en Java

Écrit par

Lewis Gavin

feature java dto

18 novembre 2022

0 minutes de lecture

Les tests sont une bonne pratique essentielle lors du développement de logiciels. Les tests unitaires font partie des nombreuses stratégies qui permettent de vérifier que notre code est fonctionnel et optimal. En tant que développeurs, nous pouvons écrire des tests unitaires pour vérifier des composants individuels (unités) du code de l’application, comme une méthode précise. L’idée consiste à écrire un ou plusieurs tests unitaires pour chaque partie du code et à les exécuter à chaque modification afin de détecter les défauts dès leur introduction dans la base de code. Pour du code nouveau, les tests doivent être ajoutés en même temps que le code (voire avant). Pour du code existant, si aucun test n’est déjà présent, il faut en ajouter afin de couvrir une grande partie — sinon la totalité — des chemins d’exécution de la logique de l’application.

Les tests unitaires visent à supprimer toutes les dépendances externes et à confirmer qu’un morceau de code précis se comporte comme prévu dans différentes situations. Il peut s’agir d’appeler plusieurs fois une méthode, chaque fois avec de nouveaux paramètres, et de vérifier qu’elle renvoie la valeur correcte, déclenche une exception ou exécute une tâche précise.

Parmi les frameworks de tests unitaires disponibles, de nombreux développeurs Java utilisent JUnit. Dans cet article, nous allons apprendre à installer et à utiliser JUnit 5 pour écrire des tests unitaires pour du code Java. Nous utiliserons l’environnement de développement intégré (IDE) VSCode pour écrire nos tests, et Java 11 avec Maven pour les exécuter. Toutefois, des outils comme Eclipse et IntelliJ fonctionnent de façon similaire et vous permettront de suivre les étapes.

Pour découvrir d’autres outils de vérification de votre code Java, consultez nos outils de revue de code Java ou notre article sur la sécurité en Java, qui vous apportera des connaissances de base supplémentaires.

Comment écrire votre premier test unitaire en Java

Dans cette section, nous allons installer le framework JUnit et écrire quelques tests unitaires. Nous exécuterons ensuite les tests sur ce projet de code exemple. Le projet est préconfiguré avec le code de l’application et un modèle de classe de test qui contient tout ce dont nous avons besoin pour commencer à ajouter des tests.

Avant de commencer à écrire nos tests, examinons le code d’exemple.

package com.snyk.unittestdemo;

public class App 
{
    public static void main( String[] args )
    {
        try {
            System.out.println(generateUpdateUserFirstNameStatement("John", "abcdef1234567"));
        }
        catch (Error e){
            e.printStackTrace();
        }
    }

    public static String generateUpdateUserFirstNameStatement(String firstName, String userId) throws Error{
        if(userId.contains(";") || firstName.contains(";")){
            throw new Error("parameters may contain SQL injection");
        }
        return "UPDATE TABLE user SET first_name = '" + firstName + "' WHERE user_id = '" + userId +"';" ;
    }

}

Notre application comporte une méthode main qui appelle la méthode generateUpdateUserFirstNameStatement et affiche le résultat. Si l’appel à la méthode generateUpdateUserFirstNameStatement déclenche une erreur, l’application intercepte l’exception et affiche la trace de la pile.

La méthode generateUpdateUserFirstNameStatement est une méthode simple qui accepte deux paramètres de type chaîne de caractères et les utilise pour générer une instruction SQL UPDATE. Le code déclenche une erreur si l’un des paramètres contient un point-virgule, car cela peut indiquer une injection SQL dans l’entrée.

Cette méthode se prête parfaitement aux tests unitaires, car nous voulons vérifier son fonctionnement dans deux situations. D’abord, lorsque nous lui transmettons deux chaînes de caractères classiques en paramètres, nous nous attendons à obtenir une chaîne contenant l’instruction SQL. Ensuite, si nous fournissons en second paramètre une chaîne contenant une injection SQL, nous nous attendons à ce que la méthode déclenche une erreur. Un test unitaire nous permet de vérifier ces deux cas.

Pour commencer, nous devons installer quelques packages Maven, notamment le maven-surefire-plugin, qui comprend la bibliothèque JUnit. Nous devons également indiquer à Maven que notre application dépend de JUnit lors de l’exécution des tests.

Ouvrons le fichier pom.xml fourni et ajoutons le code de dépendance suivant dans la section correspondante, à la ligne 21.

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>

Une fois cette étape terminée, enregistrez le fichier.

Nous pouvons maintenant utiliser Maven pour installer les packages. Pour ce faire dans VSCode, développez le menu Maven en bas à gauche, faites un clic droit sur le projet, puis cliquez sur install. Si vous utilisez un autre IDE, la procédure peut être différente.

Visual Studio Code affichant le fichier pom.xml d’un projet Java avec une dépendance de test JUnit 4.11 et le menu des commandes Maven ouvert

Si vous ne savez pas comment procéder dans votre IDE, vous pouvez toujours installer les dépendances depuis la ligne de commande. Dans un terminal, accédez au répertoire racine de votre projet, puis exécutez la commande Maven suivante pour installer les dépendances.

Remarque : si Maven n’est pas installé sur votre machine, suivez les instructions d’installation avant d’exécuter cette commande.

mvn install -f pom.xml

Une fois l’opération terminée, Maven aura installé les plugins indiqués dans notre fichier pom.xml file, notamment la bibliothèque JUnit. Lors de l’exécution des tests, Maven sait qu’il doit utiliser JUnit, que nous avons défini comme dépendance de test à l’aide de <scope>test</scope> dans la configuration.

Sortie du terminal montrant des tests unitaires Java sans échec et un résultat Maven « BUILD SUCCESS » en vert.

Comme le montre le résultat ci-dessus, la fin de l’installation affiche les informations relatives aux tests. Toutefois, aucun test n’est configuré pour le moment : le nombre de tests exécutés est donc de 0. Ajoutons deux tests unitaires à notre application.

Pour commencer, ouvrez le fichier src/test/java/com/snyk/unittestdemo/AppTest.java, que Maven exécutera pour lancer nos tests. Nous devons d’abord importer les packages JUnit nécessaires. Ajoutez les deux imports suivants au début du fichier :

import org.junit.Test;

import static org.junit.Assert.assertTrue;

Le premier import nous donne accès à l’annotation de test JUnit, qui nous permet de définir nos méthodes comme des tests. Le second importe la méthode assertTrue fournie par JUnit. Nous l’utilisons pour vérifier si une condition est vraie. Si c’est le cas, le test réussit. Sinon, il échoue.

Ajoutons notre premier test. Il vérifiera que notre méthode generateUpdateUserFirstNameStatement renvoie le résultat correct lorsqu’elle reçoit deux chaînes de caractères classiques. Dans la classe AppTest, ajoutez la méthode suivante.

@Test
public void shouldGenerateUpdateStatement()
{
    String actual = App.generateUpdateUserFirstNameStatement("John", "abcdef1234567");
    String expected = "UPDATE TABLE user SET first_name = 'John' WHERE user_id = 'abcdef1234567';";
    assertTrue( actual.equals(expected) );
}

Nous avons défini la méthode comme un test à l’aide de l’annotation @Test. Nous avons ensuite utilisé la méthode importée assertTrue pour vérifier le résultat de notre méthode generateUpdateUserFirstNameStatement. Nous lui avons fourni deux chaînes de caractères — John et abcdef1234567 — et voulons vérifier que la fonction renvoie la chaîne attendue. Si notre méthode fonctionne correctement, ce test devrait réussir.

Enregistrez le fichier et exécutez le test pour vérifier qu’il réussit. Dans VSCode, vous pouvez faire un clic droit sur le projet Maven et cliquer sur test.

Visual Studio Code affichant un fichier Java AppTest avec JUnit et la sortie du terminal Maven : un test réussi et une compilation sans erreur

Vous pouvez également exécuter cette commande depuis le terminal. Pour cela, ouvrez le terminal, accédez au dossier du projet, puis exécutez la commande suivante.

mvn test -f pom.xml

Cette commande demande à Maven de compiler l’application et d’exécuter les tests. Le résultat des tests devrait maintenant indiquer qu’un test a été exécuté et qu’aucun échec n’a été constaté.

Sortie du terminal montrant l’exécution d’un test unitaire Java sans échec, erreur ni test ignoré, suivie d’un message BUILD SUCCESS.

Modifions maintenant légèrement la méthode generateUpdateUserFirstNameStatement, en changeant l’instruction UPDATE renvoyée par la fonction. Relancez les tests pour voir comment Maven signale un échec.

Sortie du terminal indiquant l’échec d’un test unitaire Java, avec un échec d’assertion dans AppTest.shouldGenerateUpdateStatement et l’échec d’une compilation Maven.

Le résultat change et nous indique maintenant qu’un test a échoué. Sous l’en-tête Results:, vous pouvez voir le nombre et le type des échecs. Dans ce cas, le résultat précise le nom de notre méthode de test generateUpdateUserFirstNameStatement ainsi que le numéro de la ligne où le test a échoué (ligne 14). N’oubliez pas d’annuler les modifications qui ont cassé la fonction.

Nous pouvons également vérifier que notre fonction déclenche bien une erreur comme prévu, en utilisant une approche légèrement différente de la méthode assertTrue. Pour commencer, ajoutez la méthode de test suivante à la classe de test.

@Test(expected = Error.class)
public void shouldThrowErrorForSQLInjection()
{
    App.generateUpdateUserFirstNameStatement("John", "abcdef1234567; DROP TABLE user;");
}

Ici, nous avons utilisé l’annotation @Test pour indiquer une valeur attendue. Nous nous attendons à ce que notre méthode déclenche une instance de la classe Error, car c’est ainsi que nous l’avons programmée pour gérer la réception d’une injection SQL dans l’un ou l’autre paramètre. Nous pouvons maintenant exécuter les tests et vérifier qu’ils réussissent.

Sortie du terminal montrant l’exécution réussie de tests unitaires Java : deux tests, aucun échec ni erreur, et le message BUILD SUCCESS.

Nous avons implémenté avec succès nos premiers tests unitaires Java avec JUnit. Ils nous permettent de vérifier que notre code fonctionne comme prévu et produit les résultats corrects. Dans le cas contraire, notre test échouera.

Il est essentiel de protéger nos applications contre les vulnérabilités, notamment celles qui nous exposent aux injections SQL malveillantes. Ajouter un test de ce type peut éviter qu’un développeur introduise cette vulnérabilité à l’avenir. Les tests renforcent la confiance dans notre code et offrent un filet de sécurité aux développeurs qui y travailleront par la suite. Découvrez ici d’autres bonnes pratiques de sécurité Java.

Snyk Code est un autre outil capable de détecter les mauvaises pratiques de sécurité dont les développeurs n’ont pas forcément conscience et pour lesquelles ils n’ont pas écrit de tests. Il peut notamment repérer le code vulnérable aux injections SQL, ainsi que les informations sensibles codées en dur, comme les secrets d’API et les informations permettant d’identifier une personne.

Le test définit un contrat qui décrit le comportement attendu de la méthode. Si un développeur souhaite mettre à jour la méthode generateUpdateUserFirstNameStatement et la casse involontairement — comme nous l’avons fait pour notre deuxième test —, le test unitaire échoue et fournit des informations sur le problème. Cette pratique ajoute une couche de protection contre la rupture des fonctionnalités essentielles et la mise en production de modifications instables ou dangereuses.

Conclusion

Comme nous l’avons vu dans ce tutoriel, écrire des tests unitaires est un moyen simple de vérifier que notre code se comportera comme prévu dans toutes sortes de situations. De plus, les tests unitaires offrent une protection contre les erreurs dans les projets collaboratifs : ils empêchent les autres développeurs de casser accidentellement notre code ou d’introduire des vulnérabilités. Bien qu’ils ne soient pas le seul moyen de tester une application, les tests unitaires devraient faire partie de la boîte à outils de tout développeur.

Consultez ces articles connexes pour approfondir vos connaissances techniques sur Java :

Lancez-vous dans les compétitions Capture The Flag

Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.

Lire la suite

Blog

Les modèles de pointe ont trouvé les vulnérabilités. Seul l’attaquant a trouvé les chaînes d’exploitation.

L’analyse statique a détecté les failles, mais seuls des tests d’attaque en conditions réelles ont prouvé comment elles pouvaient être enchaînées pour provoquer des compromissions. Comparaison d’Evo COS, de Claude Security et de Claude Code Security.

feature insights context
Blog

Les attaques autonomes sont déjà là. La défense doit suivre leur rythme.

Les attaquants autonomes réduisent la fenêtre de défense. Découvrez comment la découverte, la correction, la validation et la prévention continues peuvent aider les équipes de sécurité à suivre le rythme.

Blog

Pourquoi les agents de codage IA créent-ils sans cesse des failles de contrôle d’accès ?

Les agents de codage IA peuvent générer une logique d’autorisation qui compile et passe la revue, tout en exposant les données d’un tenant à un autre. Découvrez pourquoi les failles de contrôle d’accès sont difficiles à détecter et comment les prévenir.