« Retour

Chronométrer ses étapes de tests automatisés (Java)

Vous avez un test fonctionnel automatisé en Java (Selenium ou autre), et vous souhaiteriez enregistrer dans un fichier CSV la durée de chacune de ses étapes. Cela peut être en effet très utile pour surveiller l’évolution des performances de l’applicatif à tester !

Pour comprendre à quoi cela pourrait nous servir, voici un cas d’usage.

Cas d’usage

Lundi, on lance le test automatisé chronométré. Le parcours d’inscription dure environ 40 secondes ; les durées de toutes les étapes sont enregistrées dans un rapport au format CSV. Le lendemain, un refacto du back a lieu. On relance le test, cette fois l’inscription dure 45 secondes. On observe le rapport CSV. On identifie l’étape où ça coince pour se concentrer dessus. On voit que le temps de réponse d’une API a augmenté de 7 secondes (mince !), et qu’un autre temps a diminué de 2 secondes (chouette !) Un correctif est livré, on relance le test. Le parcours dure maintenant 38 secondes. Ces résultats sont communiqués et l’équipe est congratulée. Tout est bien qui finit bien !

Qu’est-ce que ça change par rapport à d’habitude ?

On documente mieux les mauvaises nouvelles

« C’est plus lent qu’avant. » Voilà une phrase que tout le monde souhaite prendre au sérieux. Le problème est qu’elle est fort imprécise. Plus lent comment ? Il faut se baser sur les souvenirs d’une personne. Si elle est du genre à forcer le trait, on peut entrer dans de bien épineuses discussions. Et si on est plusieurs à s’y mettre… « Moi ça a toujours été lent, est-ce que c’est à cause de ma machine ? » Etc. Bref, on cherche à éviter au maximum ce genre d’inutiles échanges. D’autant que tout ça nous rappelle à quel point les exigences non-fonctionnelles ont été mises de côté, comme trop souvent…

Avec ce type de rapport, il va devenir très simple de porter un regard objectif sur la performance des applicatifs.

… mais aussi les bonnes !

Au détour d’une refonte, vous constaterez peut-être que certaines étapes durent moins longtemps qu’avant. Ce sera désormais plus simple de le prouver. Eh oui, en tant que QA, on peut aussi aussi remonter des effets de bord positifs ! Cela permet de donner le sourire à l’équipe et surtout de pouvoir capitaliser dessus.

Objection votre honneur !

« Ah oui certes, mais pourquoi ne pas utiliser un outil dédié à ce type de test, par exemple Gatling ? »

Loin de nous l’envie de réinventer la roue ! La solution que nous allons proposer a pour objectif de :

  • S’intégrer à des tests existants en un rien de temps
  • Répondre à un besoin d’enregistrement des performances très simplement
  • Fournir un rapport frugal mais très clair
  • S’intégrer à un parcours utilisateur en passant par le front

Nous vous invitons néanmoins à garder un point à l’esprit. La durée des étapes ne dépend pas seulement des performances de l’applicatif (et autres facteurs tels que son environnement technique, la connexion internet, etc.) ; elle dépend aussi de la vitesse d’exécution du webdriver, qui dépend en bonne partie de votre script lui-même !

Si jamais vous changez votre script de test, toutes vos métriques passées peuvent devenir obsolètes. Il est donc important de stabiliser vos tests, notamment en optimisant les temps d’attente des éléments de la page web, avant de vous lancer dans cette démarche.

Balance le code !

Ok, ok, le voici ! Copiez-collez-le sauvagement si ça vous chante. Et si vous voulez plus d’explications, rendez-vous après ce gros bloc de Java.

Le gros bloc de code que vous attendiez

import org.junit.Test;
import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class PerfTest {

    ArrayList<BaliseTemporelle> balisesTemporelles = new ArrayList<>();

    @Test
    public void exemplePourMontrer() throws InterruptedException {
        String nomScenario = "Création de compte";
        BaliseTemporelle init = new BaliseTemporelle("Initialisation de la première durée"); // Cette première balise temporelle n'apparaîtra pas dans le fichier.
        balisesTemporelles.add(init);
        Thread.sleep(2000); // Ici, mettre lesdites étapes de test. Pour une meilleure lisibilité, nous ne mettons que des temps de pause, qu'on pourra retrouver dans le fichier de rapport.
        BaliseTemporelle accesSite = new BaliseTemporelle("Ouverture du navigateur et accès à telle URL");
        balisesTemporelles.add(accesSite); // On ajoute l'étape une fois qu'elle est terminée
        Thread.sleep(4000);
        BaliseTemporelle affichageFormulaireInscription = new BaliseTemporelle("Affichage du formulaire d'inscription");
        balisesTemporelles.add(affichageFormulaireInscription);
        Thread.sleep(6000);
        BaliseTemporelle remplissageFormulaireInscription = new BaliseTemporelle("Remplissage");
        balisesTemporelles.add(remplissageFormulaireInscription);
        Thread.sleep(8000);
        BaliseTemporelle validationFormulaireInscription = new BaliseTemporelle("Validation du formulaire d'inscription");
        balisesTemporelles.add(validationFormulaireInscription);
        enregistrerDurees(nomScenario);
    }

    // Ce qui suit est un ensemble de fonctions que vous devrez, de préférence, ranger ailleurs.

    private class BaliseTemporelle {
        String nom;
        Timestamp timestamp;

        public BaliseTemporelle(String nom){
            this.nom = nom;
            timestamp = new Timestamp(System.currentTimeMillis());
        }

        public Timestamp getTimestamp(){
            return timestamp;
        }

        public String getNom(){
            return nom;
        }
    }

    private ArrayList<Long> getDureesEtapes(){
        Timestamp premier = balisesTemporelles.get(0).getTimestamp();
        ArrayList<Long> durees = new ArrayList<>();
        for (BaliseTemporelle baliseTemporelle : balisesTemporelles) {
            Timestamp deuxieme = baliseTemporelle.getTimestamp();
            if (premier != deuxieme) {
                long diffTimeSecondes = (deuxieme.getTime() - premier.getTime()) / 1000;
                durees.add(diffTimeSecondes);
                premier = deuxieme;
            }
        }
        return durees;
    }

    public void enregistrerDurees(String nomScenario) {
        ArrayList<Long> durees = getDureesEtapes();
        StringBuilder sbDurees = new StringBuilder();
        Long total = new Long(0);
        for (Long duree : durees) {
            total += duree;
            sbDurees.append(duree);
            sbDurees.append(";");
        }

        try {
            File file = new File("src\\test\\java\\utils\\" + nomScenario  + ".csv"); // A remplacer par le chemin de votre choix...
            boolean creerFichier = file.createNewFile();
            BufferedReader br = new BufferedReader(new FileReader(file));
            FileWriter fw = new FileWriter(file.getAbsolutePath(), true);
            BufferedWriter bw = new BufferedWriter(fw);
            if(creerFichier){
                StringBuilder sbNomEtapes = new StringBuilder();
                balisesTemporelles.remove(0); // On n'a pas besoin d'afficher le nom de la première étape vu que ce sont les durées qu'on affiche (diff entre étape n et étape n-1.
                for (BaliseTemporelle etape : balisesTemporelles) {
                    sbNomEtapes.append(etape.getNom());
                    sbNomEtapes.append(";");
                }
                bw.write("Date;" + sbNomEtapes.toString() + "Total\n");
            }
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
            String date = sdf.format(new Date());
            bw.write(date + ";" + sbDurees.toString() + total + "\n");
            br.close();
            bw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Hé bien, c’était un gros bloc ! Mais rassurez-vous, c’est tout ce dont vous aurez besoin !

Quelques explications

Ce petit « cas de test » (vous l’aurez compris en lisant le code, il ne teste rien) va alimenter, à chaque exécution, un fichier nommé « Création de compte.csv ». Le nom de ce fichier dépend de la variable nomScenario.

Le contenu de ce fichier, ouvert dans Excel, ressemble à ça après deux lancements du test :

Date

Ouverture du navigateur et accès à telle URL

Affichage du formulaire d'inscription

Remplissage

Validation du formulaire d'inscription

Total

2020-07-30-01-37-15

2

4

6

8

20

2020-10-22-03-05-40

2

4

6

8

20

La durée qui s’affiche dans chacune des cellules est calculée en soustrayant l’horodatage d’une balise temporelle de la balise suivante (dans la fonction "enregistrerDurees"). Le nom de la première balise temporelle (voir la classe BaliseTemporelle) n’apparaît pas dans le tableau, car elle correspond au temps 0 du test.

Pas besoin de créer le fichier Excel à l’avance, le script gère tout seul la création et la modification. Assurez-vous simplement de supprimer le fichier Excel dès que vous souhaitez changer votre script, car les durées ne seront plus bonnes, et les noms des balises temporelles ne correspondront peut-être plus à celles d’avant. Vérifiez bien aussi que le chemin indiqué lors de l’initialisation de la variable « File » est valide, ou changez-le carrément.

C’est tout ce qu’il vous faut ! Bon chronométrage et n’hésitez pas à poser vos questions si vous en avez !

Un avis ? Un commentaire ?

Cet espace est pour vous.