Aller au contenu
KésacoTestTDD

Le Test Driven Development (TDD), pour quoi faire ?

Pourquoi une approche TDD est incontournable pour développer sereinement et garantir une excellente couverture?

Pourquoi adopter une approche TDD?

Le TDD, ou développement piloté par les tests en français, est une méthode de développement de logiciel qui consiste à concevoir un logiciel par des itérations successives très courtes. Retrouvez la définition complète dans cet article.

Souvent vu par les moins expérimentés comme une perte de temps dans leurs cycles de développement, le TDD répond au contraire à plusieurs problématiques de qualité.

Pour comprendre le besoin

Lorsqu'on développe en TDD, les tests répondent directement au besoin métier. De ce fait, développer en TDD aidera l'équipe de développement à comprendre les différents cas fonctionnels. Chaque test en traitant un, leur simple lecture permettra à un nouveau venu de comprendre les différentes contraintes métier.

Dans le cas d'une voiture, rien qu'en lisant les tests, on comprend qu'une voiture doit pouvoir rouler à une certaine vitesse, elle doit pouvoir tourner, accueillir un certain nombre de passagers, etc...

Pour couvrir le besoin

Chaque cas du besoin métier fait l'objet d'un test. À l'issue du développement, les tests couvrent le besoin tel qu'il est décrit. La couverture de tests est alors optimale, ce qui permet de garantir un certain niveau de confiance dans le produit développé.

Dans le cas d'une voiture, quels que soient les ajout demandés par le client, elle continuera de pouvoir rouler, tourner, etc...

Pour tester le "quoi" et non pas le "comment"

Le TDD est principalement orienté vers le métier. En cas de refonte technique de l'application, les tests n'ont pas vocation à évoluer, car ils ne doivent pas dépendre de la manière dont le besoin a été implémenté. Cela permet donc, à l'issue de la refonte, de vérifier qu'il n'y a pas de régression.

Dans le cas d'une voiture, on ne s'intéresse pas à comment elle fait pour rouler, mais bien au fait qu'elle roule. De ce fait, quelle que soit l'architecture adoptée, et en cas de refonte de l'architecture, les tests garantiront que le besoin métier reste rempli.

Un exemple de cette approche avec Fibonacci

Specification : fibo(0) doit retourner 0

Test

public class FiboTest {
    @Test
    void fibo0_shouldReturn0(){
        Assertions.assertEquals(0, Computation.fibo(0));
    }
}

Implémentation

public class Computation {
    public static int fibo(int index){
        return 0;
    }
}

Pas de refactoring pour le moment


Specification : fibo(1) doit retourner 1

Test

public class FiboTest {
    @Test
    void fibo0_shouldReturn0(){
        Assertions.assertEquals(0, Computation.fibo(0));
    }
    
    @Test
    void fibo1_shouldReturn1(){
        Assertions.assertEquals(1, Computation.fibo(1));
    }

}

Implémentation

public class Computation {
    public static int fibo(int index){
        return index==0?0:index;
    }
}

Refactoring

public class Computation {
    public static int fibo(int index){
        return index;
    }
}

Specification : fibo(n) doit retourner fibo(n-1)+fibo(n-2) pour n>=2

Test

public class FiboTest {
    @Test
    void fibo0_shouldReturn0(){
        Assertions.assertEquals(0, Computation.fibo(0));
    }
    
    @Test
    void fibo1_shouldReturn1(){
        Assertions.assertEquals(1, Computation.fibo(1));
    }
    
    @Test
    void fibo4_shouldReturn_fibo3Plusfibo2(){
        var fibo3 = Computation.fibo(3);
        var fibo2 = Computation.fibo(2);
        var expectedFibo4 = fibo3 + fibo2;
        Assertions.assertEquals(expectedFibo4, Computation.fibo(4));
    }
}

Implémentation

public class Computation {
    public static int fibo(int index) {
        return index < 2 ? index : fibo(index - 1) + fibo(index - 2);
    }
}

Refactoring

public class Computation {
    public static int fibo(int index) {
        if (index < 2) {
            return index;
        }
        
        // with memoisation, let's save our program!
        int[] fiboArray = new int[index];
        fiboArray[0] = 0;
        fiboArray[1] = 1;
        
        for (int fiboIdx = 2; fiboIdx < fiboArray.length; fiboIdx++) {
            fiboArray[fiboIdx] = fiboArray[fiboIdx - 1] + fiboArray[fiboIdx - 2];
        }
        
        return fiboArray[index - 1] + fiboArray[index - 2];
    }
}

Conclusion : le TDD, une approche de développement au service du besoin métier

Le TDD permet dans un premier temps de comprendre le besoin métier. La simple lecture des tests permet de comprendre les spécifications. Ces tests étant pérennes, ils permettent de garantir la non-régression. Si cette approche est adoptée par l'équipe de développement, le client verra une application "sans bug" et considèrera donc la grande qualité de celle-ci.

Dernier