Génie Logiciel - L3

  • 20 min de lecture
  • Étiquettes: 
  • TP
  • L3

Crédits : Florian Forestier

Ressources

Erreur JDK Isima

Dans un terminal

echo "export JAVA_HOME=/usr/lib/jvm/jdk-21.0.4-oracle-x64" >> ~/.bashrc
source ~/.bashrc

TP1

TP2

TP3

TP4

Ressources vidéo

Modalités d’évaluation

Les TP1 et TP2 sont des TP de présentations de Git et Gradle, et ne sont pas évalués. Ils sont conçus pour être effectués en 3h au total.

Les TP3 (40%) et TP4 (60%) sont évalués. Les TP sont évalués selon :

  • L’aspect fonctionnel du code et le niveau d’implémentation des fonctionnalités demandées ;
  • La propreté du code.

Il est signalé que tout dépôt rendu après la date indiquée sur Moodle sera pénalisé de 5 points par jour de retard.

Les notes seront disponibles sur Moodle dès que la correction aura été effectuée.

TP1 - Gestion de version avec Git

Présentation de Git

Git est un système de gestion de versions, c’est-à-dire un logiciel qui permet de stocker un ensemble de fichiers tout en gardant une chronologie de toutes les modifications qui ont été effectuées dessus. Cela offre la possibilité de récupérer d’anciennes versions de documents et d’examiner l’historique des modifications. Cela permet également de travailler de manière distribuée, afin que plusieurs personnes puissent collaborer sur un même projet. Pour que la collaboration de plusieurs personnes soit efficace, une fonctionnalité permet de gérer les conflits lors de modifications concurrentes de la même partie d’un fichier.

Il existe deux philosophies de gestionnaire de versions :

  • L’une utilisant un système centralisé, comme CVS ou Subversion : dans ce genre de système, il n’y a qu’un seul dépôt des versions. Le serveur va donc centraliser tous les fichiers constituant un projet et contient l’historique des versions. Dans ce système, l’utilisateur va récupérer sur son poste une version des fichiers et va toujours travailler sur celle-ci. Lorsqu’il le souhaitera, il synchronisera son code avec le dépôt central pour que le code du dépôt central soit modifié. Ce système présente plusieurs défauts, le principal étant qu’il est très difficile de travailler sans connexion ;
  • L’autre un système décentralisé, comme Git ou Mercurial : dans ces systèmes, chaque utilisateur dispose d’une copie complète du dépôt, avec son historique complet. Il sera certes plus long de cloner un dépôt, mais l’utilisateur pourra alors travailler localement sur son poste, sans connexion à internet. Par ailleurs, en cas de défaillance du serveur central, le code et son historique ne sera pas perdu, puisque tous les utilisateurs disposent d’une copie complète du code source.

Git est le système de gestion de version le plus connu et le plus utilisé de nos jours. Il s’agit d’un CVS décentralisé, créé par Linus Torvalds pour la gestion du noyau Linux. Pour l’anecdote, Git a été conçu en quelques semaines, suite à la décision de BitKeeper de rendre son outil de gestion de version payant.

Démarche

Les fichiers sont stockés dans un dépôt central. Ce dépôt peut être situé sur un serveur distant, ou sur la machine locale. L’accès à un serveur distant peut se faire soit à l’aide d’un protocole spécifique à Git, soit encapsulé dans du SSH ou du HTTP pour être accessible plus facilement.

Afin de travailler, il faut récupérer une copie locale du dépôt ; c’est la copie de travail, sur laquelle les modifications seront apportées. Une fois les modifications effectuées, il faut les commiter (les regrouper pour former un “paquet de changements”), puis les transmettre au dépôt central (push). Ce dernier mettra à jour les versions si tout se passe bien, ou refusera s’il y a un conflit qu’il ne peut pas résoudre seul. Afin de faciliter la gestion des versions, il est très fortement recommandé d’indiquer la liste des modifications effectuées. De la même manière, il est recommandé de fréquemment envoyer ses modifications et récupérer celles des autres, pour rester synchronisé, et éviter les conflits.

Utilisation de Git

Configuration initiale

Avant de commencer, nous allons créer un environnement de travail. Dans un terminal, tapez les commandes suivantes :

  • mkdir -p ~/TPGenieLog/Git
  • cd ~/TPGenieLog/Git

Nous allons ensuite configurer Git. Chacun de nos commits dispose en effet du nom de l’auteur des modifications, et son adresse mail. Il faut donc configurer Git pour qu’il les connaisse :

  • git config --global user.name "Prénom Nom"
  • git config --global user.email "prenom.nom@etu.uca.fr"

Vous pouvez afficher votre configuration avec la commande git config --list .

Commandes de base

Le programme de base (client) ne fonctionne qu’en ligne de commande. Il existe cependant de nombreuses interfaces graphiques (gitGUI, tortoise, etc). La majorité des IDEs modernes embarquent également un visualiseur Git. Ces clients graphiques présentent tous l’inconvénient d’être incomplets et de fonctionner en “magie noire”, aussi, il est déconseillé de s’en servir pour autre chose que de la lecture.

Création d’un dépôt

Tout d’abord, nous allons initialiser notre dépôt Git en local. Dans le dossier ~/TpGenieLog/Git créé précédemment, nous allons taper la commande suivante : git init .

Cette commande va créer un dossier .git dans votre dossier courant. Ce répertoire contient toutes les informations nécessaires à Git pour gérer son dépôt. Les données ne doivent jamais être éditées à la main. L’arborescence est la suivante :

  • config : contient les options de configuration spécifique au projet
  • description : fichier utilisé pour parcourir le dépôt git via interface graphique
  • HEAD : lien symbolique vers la branche courante. En général, redirige vers refs/heads/master.
  • hooks/ : contient les scripts exécutés avant ou après certaines commandes (commit, push, etc)
  • info/ : contient divers fichiers de configuration
  • objects/ : contient tout le contenu de la base de code versionné
  • refs/ : contient toutes les références du dépôt (stashes, tags, branches distantes et locales, etc).

Voir le statut du dépôt local

À tout moment, vous pouvez connaître l’état du dépôt en utilisant la commande git status . Cette commande va indiquer l’ensemble des modifications depuis votre dernier commit. Actuellement, elle devrait vous indiquer qu’aucun changement n’a eu lieu. Mais cela va vite changer !

Créons maintenant quelques fichiers :

  • echo "Bonjour !" > bonjour.txt
  • echo "Un autre fichier" > fichier.txt
  • echo "### Et un dernier pour la route" > route.md

En relançant votre commande git status , vous allez constater que git vous indique plusieurs fichiers non-suivis.

Ajouter un fichier

Pour commencer à suivre les modifications dans un fichier (et l’ajouter à votre prochain commit), on utilise la commande git add nom_de_fichier . Il est possible de stipuler plusieurs fichiers d’un coup, en listant chaque fichier un par un (exemple : git add bonjour.txt fichier.txt ), ou en utilisant git add . , qui ajoute tous les fichiers au commit.

Ajoutez l’ensemble des fichiers (avec la commande que vous souhaitez), et relancez un git status . Vous devriez avoir un message de Git indiquant que les fichiers sont suivis pour le changement.

Commiter les changements

Maintenant que nous avons fait des changements, nous pouvons commiter, c’est-à-dire fixer nos changements dans l’historique de Git. La commande est la suivante : git commit -m "mon_message_de_commit" .

En relançant la commande git status , git doit vous indiquer que la liste de changement est à nouveau vide. Cela signifie que vos changements sont désormais présents dans Git, et qu’ils seront toujours accessibles dans l’historique !

Voir l’historique du dépôt

Vous pouvez regarder l’historique avec la commande git log . Ce dernier devrait normalement afficher un seul bloc, contenant :

  • Le hash du commit (un ensemble de chiffres et de lettre aléatoire permettant d’identifier le commit)
  • La branche sur laquelle les changements ont été poussés
  • L’auteur du commit
  • La date
  • Et enfin, le message de commit

Maintenant, nous allons ajouter une seconde série de modifications. Ajoutez du contenu dans le fichier “bonjour.txt”, et relancez un git status . Vous devriez voir les changements que vous avez effectués.

Voir les différences sur le dépôt local

Une autre commande très utile est git diff . Cette commande va vous permettre de voir l’ensemble des changements effectués dans un fichier depuis votre dernier commit. Une ligne commençant par un - est une ligne supprimée, une ligne commençant par un +est une ligne ajoutée. Si vous changez un caractère dans une ligne, la ligne entière sera considérée comme effacée, et ajoutée.

Commitons à nouveau nos modifications (vous avez les commandes plus haut). git log devrait désormais afficher 2 commits !

Réparer ses erreurs

Malheur, vous vous rendez compte que vous avez fait une vilaine faute dans un message de commit ! Heureusement, la fonction “amend” vous permet de corriger cela sans être vu : git commit --amend -m "Update my message !" . Relancer la commande git log vous permettra de voir que le message a bien été mis à jour.

Retourner en arrière

Parfois, vous aurez envie de revenir en arrière, car vous vous rendrez compte qu’une modification dans votre code a eu des impacts indésirables. git revert est là pour vous !

Exécutons la commande git revert HEAD. Quittez vi avec :q. Relancez git log : que s’est-il passé ?

Il est possible de revenir en arrière de plusieurs versions en spécifiant le nombre de commits que l’on souhaite annuler : git revert HEAD~2 permet ainsi de revenir en arrière de 2 commits. Lancez la commande, et constatez les changements en explorant le contenu de votre dépôt (avec ls par exemple).

Maintenant, faites un dernier git revert pour revenir à l’état initial du dépôt.

Ignorer des fichiers

Parfois, vous souhaiterez ignorer des fichiers de votre arborescence Git (fichier de base de données, de configuration, etc). Un moyen très simple de le faire est d’ajouter un fichier .gitignore à la racine de notre projet, et d’y noter les fichiers à exclure. Par exemple :

configuration.txt
base.h2
dossier/ #Va exclure le dossier entier
*.h2 #Va exclure tout les fichiers terminant par .h2

Créez un fichier .gitignore avec le contenu fourni ci-dessus, puis créez un fichier “configuration.txt”. Lancez un git status. Que constatez-vous ? Ajoutez et commitez les modifications.

Un site très utile au quotidien est gitignore.io, qui vous permet de générer des fichiers .gitignore à la volée.

Gérer des branches

Les branches permettent de contenir des versions déviant de la ligne de développement principale. Cette fonctionnalité est très utilisée, notamment pour pouvoir expérimenter du code sans toucher la branche principale.

À l’initialisation, une première branche est créée. Cette branche se nomme master. Il est possible de voir la liste des branches avec la commande git branch . La branche actuelle est notée d’un astérisque.

Pour créer une branche, il existe deux options :

  • git branch nom_branche , va créer une branche sans vous basculer dessus. Il faudra basculer avec git checkout nom_branche
  • git checkout -b nom_branche , va créer la branche et vous positionner dessus.

Créez une nouvelle branche experimental , et accédez-y.

Créez un fichier experiment.txt avec du contenu dedans (ce que vous voulez). Commitez vos changements, et vérifiez avec git log . Basculez maintenant sur la branche master : git checkout master . Relancez git log . Que constatez-vous ? Idem pour la commande ls .

Comme vous pouvez le voir, ni git log ni la commande ls ne voient votre fichier experiment.txt. Ce qui est normal, comme vous l’avez créé sur une autre branche !

Fusionner des branches

Maintenant, lançons la commande git merge experimental . Cette commande va récupérer les changements effectués dans la branche experimental , et les rapatrier dans master .

Si vous relancez ls ou git log, vous devriez désormais voir le fichier experiment.txt et son commit associé ! Nous pouvons désormais supprimer la branche experimental qui ne sert plus à rien.

Supprimer une branche

Pour supprimer une branche, il suffit d’utiliser la commande git branch avec l’argument -d . Exemple : git branch -d experimental . Vous pouvez vérifier que la branche a bien été supprimée en listant vos branches.

Gérer les conflits

Lorsque vous fusionnez des branches, il est possible que vous obteniez un conflit ; c’est-à-dire une situation que Git ne sait pas résoudre tout seul. Cela arrive notamment lorsque deux personnes modifient le même fichier sur deux branches différentes.

Créons une situation de conflit :

  • git checkout -b conflit
  • echo "bonjour" > experiment.txt
  • git add . && git commit -m "bonjour"
  • git checkout master
  • echo "coucou" > experiment.txt
  • git add . && git commit -m "coucou"

Ici, nous venons d’écrire “bonjour” dans le fichier experiment.txt sur la branche conflit, et coucou dans le même fichier sur la branche master. Tentons de merger notre branche : git merge conflit .

Comme attendu, Git nous renvoie une erreur indiquant un conflit dans experiment.txt. À ce stade, il n’y a pas d’autre choix que de résoudre manuellement le conflit. Éditez le fichier experiment.txt (avec vi, nano, ou un autre éditeur de text).
Le contenu devrait être le suivant :

<<<<<<< HEAD
coucou
=======
bonjour
>>>>>>> conflit

La structure est assez simple : la partie située entre <<<<<<< HEAD et ======= est issu de la branche actuelle (master), et la partie entre ======= et >>>>>> conflit est issu de la branche conflit. Pour résoudre un conflit, il suffit de supprimer ces éléments, et d’arranger comme on le veut le contenu, à savoir garder un côté ou l’autre (ou les deux).

Ensuite, on rajoute un commit pour indiquer la résolution du conflit : git add . && git commit -m "conflit résolu !" . On peut alors supprimer la branche conflit.

Dépôts distants

Pour cette partie TP, nous allons utiliser une instance de GitLab, un serveur Git très utilisé en entreprise. Rendez-vous sur https://gitlab.isima.fr/, et créez un compte avec votre adresse universitaire. (Cette instance est vidée régulièrement !).

Ensuite, créez un dépôt : cliquez sur le “+” en haut à gauche de l’interface, puis sur “New Repository”. Donnez-lui un nom, et cliquez sur “Create Repository”. Votre dépôt est désormais créé.

Maintenant, nous devons indiquer à notre dépôt local que nous avons une cible distante. Pour cela, nous pouvons utiliser la commande git remote . Cette commande permet d’ajouter, modifier ou supprimer des dépôts distants à synchroniser.

Lançons la commande : git remote add origin URL . L’URL est votre dépôt est indiquée sur l’interface de GitLab, et termine par un .git .

Ensuite, nous allons pousser nos changements : git push -u origin master . Git vous demandera très probablement votre identifiant et votre mot de passe de l’instance GitLab. Vous devriez voir apparaître dans l’interface Web vos fichiers !

Maintenant, imaginons que vous avez deux ordinateurs, sur lequel votre code est présent. Allez dans ~/TPGenieLog . Nous allons cloner notre dépôt distant. Le clone permet de récupérer une copie locale du dépôt, pour y travailler dessus. git clone URL SecondPC . Le dépôt git sera cloné dans un dossier nommé SecondPC.

Dans le dossier SecondPC, effectuez des modifications, commitez et poussez les modifications.

Retournez dans le dossier ~/TPGenieLog/Git : vos modifications apportées ne sont pas encore présentes. Vous pouvez les récupérer avec git pull .

Conclusion

Nous avons vu dans ce TP quelques possibilités offertes par Git. Cependant, nous sommes loin d’avoir tout vu ! Git dispose en effet de commandes très poussées permettant d’effectuer de nombreuses actions (rebase, cherry pick, etc).

Grâce à ce TP, vous êtes désormais en mesure d’utiliser Git dans vos projets universitaires et personnels.

Si vous souhaitez héberger du code, n’hésitez pas à aller voir les sites GitHub et GitLab, qui permettent de créer gratuitement des dépôts Git.

TP2 - Gradle, votre ami pour le Java

Gradle est un logiciel permettant de construire automatiquement des projets sur plusieurs langages, notamment Java, Groovy, ou C++. Grâce à un fichier de configuration, vous allez pouvoir indiquer à Gradle l’ensemble des dépendances de votre projet, les étapes de construction (la phase de build), et automatiser tout ce pan de la gestion de votre code. Désormais, Gradle s’occupe de maintenir vos dépendances et de les télécharger si besoin est, mais également de créer le binaire de votre application, de démarrer des tests automatiquement au build, et bien plus encore...

Premier usage

Pour commencer, clonez le projet de départ de ce TP sur votre VM (ça tombe bien, vous venez de découvrir Git !).

Dans ce projet, nous avons un ensemble de fichiers et de dossiers :

  • gradle/ : Ce dossier contient le wrapper de Gradle (c’est-à-dire, l’exécutable)
  • src/ : Ce dossier contient nos sources Java
  • gradlew et gradlew.bat : Ce sont les fichiers pour lancer Gradle, le premier sous Linux, le second sous Windows.
  • build.gradle : C’est le fichier qui nous permet de configurer notre Gradle !

Avant de regarder plus en détail ce dernier fichier, lançons notre première commande Gradle : ./gradlew tasks va vous permettre de lister les tâches que Gradle va pouvoir accomplir pour vous sur ce projet.

Comme vous pouvez le constater avec le résultat de la commande, Gradle sait effectuer de nombreuses actions très utiles au quotidien (builder votre projet, lancer les tests, vérifier les dépendances, etc). Regardons un peu plus en détail comment tout cela fonctionne, avec le fichier build.gradle.

Gradle sous la loupe

apply plugin: 'java'
apply plugin: 'application'

mainClassName='com.uca.StartServer'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.freemarker:freemarker:2.3.30'
    implementation 'com.sparkjava:spark-core:2.9.3'
    implementation 'com.h2database:h2:1.4.200'
    compile 'io.jsonwebtoken:jjwt-api:0.11.2'
    runtime 'io.jsonwebtoken:jjwt-impl:0.11.2', 'io.jsonwebtoken:jjwt-jackson:0.11.2'
    compile 'org.mindrot:jbcrypt:0.4'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.11.1'
    compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.1'
}

jar {
  manifest {
        attributes 'Implementation-Title': 'Gradle Quickstart',
                    'Implementation-Version': '1.0.0',
                    'Main-Class': 'com.uca.StartServer'
    }
}

sourceSets.main.java.srcDirs = ['src']
sourceSets.test.java.srcDirs = ['src']

Revenons point par point sur ce fichier, et attardons-nous sur ce qu’il décrit.

apply plugin: 'java'
apply plugin: 'application'

Ici, nous indiquons à Gradle que nous allons utiliser des plugins. Les plugins sont des ensembles de règles et d’informations, pré-conçues par les développeurs de Gradle ou par des contributeurs, qui permettent d’éviter de réécrire les informations basiques à chaque fois. Ici, nous indiquons donc à Gradle que nous allons compiler du Java, et que nous construisons une application. Les plugins peuvent être facilement retrouvés dans le guide d’utilisateur de Gradle.

mainClassName='com.uca.StartServer'
[...]
sourceSets.main.java.srcDirs = ['src']
sourceSets.test.java.srcDirs = ['src']

Ces quelques lignes permettent d’indiquer à Gradle comment se comporter : où se trouvent les fichiers de source et de test, et quelle est la classe principale.

jar {
 manifest {
        attributes 'Implementation-Title': 'Gradle Quickstart',
                   'Implementation-Version': '1.0.0',
                   'Main-Class': 'com.uca.StartServer'
    }
}

Cette partie du fichier va permettre à Gradle de générer automatiquement le manifeste de votre application Java. Pour rappel, le fichier de manifeste est un fichier standard, inclus dans chaque programme Java pour décrire ses fonctionnalités et ses propriétés.

repositories {
    mavenCentral()
}

Nous indiquons ici à Gradle d’aller chercher toutes les dépendances sur MavenCentral, une plateforme de référence pour les dépendances et librairies Java.

dependencies {
    implementation 'org.freemarker:freemarker:2.3.30'
    implementation 'com.sparkjava:spark-core:2.9.3'
    implementation 'com.h2database:h2:1.4.200'
    compile 'io.jsonwebtoken:jjwt-api:0.11.2'
    runtime 'io.jsonwebtoken:jjwt-impl:0.11.2', 'io.jsonwebtoken:jjwt-jackson:0.11.2'
    compile 'org.mindrot:jbcrypt:0.4'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.11.1'
    compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.1'
}

Enfin, nous indiquons ici l’ensemble des dépendances que nous utilisons, et à quel moment nous les utilisons.

Et si on buildait ?

Lancez la commande ./gradlew run. Que se passe-t-il ?

Lancez la commande ./gradlew build. Que se passe-t-il ?

TP3 - Tests unitaires

Dans ce TP, on se propose d’expérimenter l’utilisation des tests unitaires en Java. Pour cela, on va réaliser une classe permettant de gérer des chiffres romains.

Rappel sur les chiffres romains

Dans la numérotation romaine, il y a sept symboles combinés de différentes manières pour composer les nombres :

  • I = 1
  • V = 5
  • X = 10
  • L = 50
  • C = 100
  • D = 500
  • M = 1000

La construction des nombres plus complexes suit les règles suivantes :

  • Les symboles sont additifs : I vaut 1, II vaut 2, VI vaut 6 (5 + 1), etc
  • Les symboles des multiples (I, X, C et M) peuvent être répétés jusqu’à trois fois. À partir de quatre, il faut soustraire du symbole suivant. Ainsi, 4 est représenté par IV, 40 s’écrit XL, etc.
  • De même, si 8 est VIII, 9 est IX.
  • Les symboles des “5” ne peuvent jamais être répétés.
  • Les chiffres romains s’écrivent du plus grand vers le plus petit et se lisent de gauche à droite. L’ordre compte : DC est 600, mais CD est 400.

Les propriétés suivantes devront être respectées :

  • Il n’existe qu’une seule manière de représenter un nombre en chiffres romains
  • Réciproquement, un nombre romain valide représente un seul nombre décimal
  • Seuls les nombres entiers compris entre 1 et 3999 inclus peuvent être représentés avec ce système

Module de conversion

Les algorithmes de conversion sont assez simples et sont donnés ci-dessous.

Conversion d’un chiffre arabe vers un chiffre romain :

Données : table des symboles (symbole, nombre) connus
Entrées : nombre entier inclus dans l'intervalle [1;3999] n
Résultat : chiffre romain
Début
    résultat = "";
    Pour chaque couple (symbole, nombre) de la table des symboles, faire :
        Tant que n \>= nombre, faire :
            résultat = résultat + symbole;
            n = n - nombre
    Retourner résultat

Conversion d’un chiffre romain vers un chiffre arabe :

Données : table des symboles (symbole, nombre) connus
Entrées : chiffre romain s
Résultat : nombre entier en décimal
Début
    résultat = 0;
    index = 0;
    Pour chaque couple (symbole, nombre) de la table des symboles,
    faire :
        Tant que SousChaine(s,index,index+Longueur(symbole)) == symbole, faire :
            résultat = résultat + nombre;
            index = index + Longueur(symbole)
    Retourner résultat

Une base de code vous est donné dans la pièce jointe au TP.

Pour simplifier la conversion, les combinaisons soustractives ont été ajoutées à la table des symboles. De plus, l’expression régulière de validation des chiffres romains vous est donnée.

Tests unitaires et TDD

Principe des tests unitaires

Les tests unitaires ont pour but de tester les fonctions (ou méthodes) à un niveau élémentaire, avec une approche “boîte noire”, c’est-à-dire que l’on ne connaît que la signature de la fonction à tester. On teste donc des unités fonctionnelles indépendantes d’un programme plus global.

Il existe des frameworks de test unitaire pour la plupart des langages de programmation, souvent inspiré de SUnit, le framework pour Smalltalk.

Les méthodes de test ne testent qu’un aspect particulier du cas, correspondant à une spécification particulière, et lèvent une exception si le résultat n’est pas celui attendu. Cette verification se fait par l’intermédiaire de méthodes spécifiques (assertEquals, assertRaises, etc). Là aussi, il existe de nombreuses bibliothèques d’assertion.

Mise en oeuvre

Nous allons suivre les principes du développement guidé par les tests, ou TDD (Test Driver Development). Cela signifie que nous allons écrire les tests avant d’écrire le code. C’est un principe mis en œuvre dans les méthodes agiles.

Les tests à effectuer sont (au moins) les suivants :

  • Tests de réussite
    • Donner les bonnes valeurs décimales pour des valeurs romaines connues
    • Donner les bonnes valeurs romaines pour des valeurs décimales connues
  • Tests d’échec :
    • Échouer pour les valeurs négatives
    • Échouer pour des valeurs hors de l’intervalle [1;3999]
    • Échouer pour des valeurs avec trop de répétitions de symboles
    • Échouer pour des valeurs avec des répétitions de paires
    • Échouer pour des valeurs avec des antécédents incorrects
  • Tests de validité :
    • Pour tout entier n inclus dans l’intervalle [1;3999], fromRoman(toRoman(n)) = n

Travail

L’idée est donc d’écrire les tests en premier, et d’implémenter les fonctionnalités petit à petit jusqu’à ce que tous les tests passent :

  • Implémentez la totalité des tests unitaires d’après les spécifications fournies
  • Implémentez les méthodes toRoman et fromRoman jusqu’à ce que tous les tests passent
  • Implémentez et testez les méthodes définies dans java.lang.Number (toString(), toDouble(), etc)
  • Faites en sorte qu’un chiffre romain soit comparable avec n’importe quel autre nombre (voir l’interface Comparable)

Le modèle fournit pour ce TP utilise l’outil Gradle. Le fichier de configuration build.gradle défini les tâches et les dépendances du projet.

Pour exécuter les tests, lancez la tâche test de gradle : ./gradlew test sous Linux.

TP4 - Implémentation de schéma UML

Dans ce TP, nous allons implémenter le modèle du TD sur la réservation de vols.

Travail

Implémentez le modèle défini en TD.

Version normale

Pour cela, commencez par implémenter la première version du paquet des voyages.

Implémentez ensuite le package réservation.

Double navigabilité

Implémentez la double navigabilité entre deux classes. Vous pourrez essayer de commencer par une double navigabilité de cardinalité 1-1, qui est plus simple.

Le problème de la double navigabilité est que chaque classe doit avoir une référence vers l’autre classe. Les attributs doivent donc être manipulés via des accesseurs et s’appeler mutuellement, en prenant garde d’éviter une boucle infinie.