Faites vos comptes

Nous allons simuler la représentation du concept de "compte client" d’une banque.

Analyse

Définissons les caractéristiques d’un compte

  • Attaché à un client

  • Dispose d’un solde (positif ou négatif)

  • Dispose ou non d’un découvert possible

Les services attendus (comprendre ce que l’on peut faire avec un compte)

  • Connaitre le nom du client

  • Pouvoir débiter une somme donnée (extrait de l’argent du compte)

  • Pouvoir créditer une somme donnée (ajouter une somme au solde)

  • Connaître si un débit est possible ou non

  • Connaitre le solde actuel

  • (optionnel) Faire un transfert d’une somme d’un compte à un autre

  • (optionnel) Connaître la liste des opérations passées sur ce compte

Conception

La conception de notre classe, à minima :

Diagram

Implémentation

Création du projet avec l’IDE

Sous Inellij, File/New/Project.

Sélectionner les mêmes options (langage Kotlin, Build IntelliJ, JDK 17)

Creation projet CompteBancaire

Conception / Implémentation de la classe Compte

Dans le dossier src/main/kotlin, création de la classe Compte.

package com.banque

class Compte constructor(val nomClient: String) {
}

Ajout d’une classe de test

À partir de l’IDE, faire un clic droit sur le nom de la classe, puis Generate…​/test

Generate test menu

Une boite de dialogue vous permet de paramétrer l’action. Le système ne voit pas la librairie Junit5 (un framework en fait). Sélectionner Fix pour permettre à l’IDE de gérer ce problème lui-même (download de Junit, puis intégration au système)

create test 1

Une fois le problème fixé, sélectionner les options setUp, Member getNomClient(). Cette dernière méthode est implicite dans la classe (mécanisme des properties)

create test 2

Exemple d’un test

Suite à la dernière action, la classe CompteTest a été crée dans la branche test.

arbo branch test

Voici le squelette du code généré :

import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

import org.junit.jupiter.api.Assertions.*

internal class CompteTest {

    @BeforeEach
    fun setUp() {
    }

    @Test
    fun getNomClient() {
    }
}

Nous allons maintenant programmer des tests unitaires portant sur la classe Compte par l’intermédiaire de ses instances (comprendre des objets de cette classe)

On utilisera les méthodes assertTrue, assertFalse, assertEquals de JUnit̀.

Exemple d’un test unitaire automatisé qui vérifie, sur la base d’un scénario imaginé pour l’occasion, un bon comportement de la méthode getNomClient.

    @Test
    fun getNomClient() {
        val c = Compte("Mezigue") (1)
        assertEquals("Mezigue", c.nomClient) (2)
    }
1 C’est l’objet à tester (déclaration et l’instanciation)
2 assertEquals est une fonction qui teste une assertion. Ici cette assertion vérifie que la valeur attendue (premier argument = ̀"Mezigue"), et bien égale au deuxième argument (une valeur rendue par l’expression c.nomClient )

Contrairement à ce que l’on pourrait s’attendre, les fonctions d’assertion de JUnit ne sont pas des fonctions booléennes.

public static void assertEquals(byte expected,
                                byte actual)
// Asserts that expected and actual are equal.

public static void assertTrue(boolean condition)
// Asserts that the supplied condition is true.

public static void assertFalse(boolean condition)
// Asserts that the supplied condition is not true.

C’est JUnit qui réceptionnera le résultat de toutes les assertions de test, puis en fera un rapport, comme nous allons le voir maintenant.

Exécution d’un test

Après avoir vérifié que nos tests sont sans erreurs de syntaxe, nous pouvons les lancer (demander leur compilation et exécution).

Le lancement des tests unitaires peut se faire directement dans l’IDE (vrai pour tout IDE)

Faire un ̀Clic droit sur le nom de la méthode.

lancement test unitaire 1
Figure 1. Lancement de l’exécution d’un test

Lancer le test, puis contrôler le résultat dans la fenêtre, ou le volet, ouverte pour l’occasion par l’IDE.

resultat lancement test unitaire
Figure 2. Exemple de rapport de test

Nous constatons que le test est passé avec succès, ce qui est bon signe.

Les différents états possibles d’un test sont

  • En erreur (ERROR). C’est un bug dans l’écriture même du test

  • En échec (FAILURE). Le test ne passe pas. C’est bon signe car il a détecté un bug dans le code testé par le test.

  • En succès (PASSED). L’nensemble des assertions dans le test sont passés avec succès. Le comportement du code testé est conforme à ce qui est attendu par le test unitaire.

La suite vous appartient…​

A vous de jouer

La méthode de développement consiste à

  1. Concevoir un scénario de test (par exemple "si je crédite le compte de 50€, je vérifie que le solde de ce compte a bien été augmenté d’autant")

  2. Concevoir un test unitaire centré sur ce scénario

  3. Lancer le test qui vérifier que la méthode crediter fonctionne comme attendu

  4. Si ce n’est pas le cas (le test à échoué), intervenir sur la méthode crediter (branche src/), puis revenir au point 2

  5. Si le test est passé, concevoir un nouveau scénario (revenir au point 1)

Vous avez 2 heures pour mener à bien ce travail. C’est à dire, vérifier et implémenter les services attendus de la classe Compte, tels qu’ils sont définis dans l' Analyse.

Bon développement !