350 likes | 515 Views
Programmation Objet en JAVA Cours 8 : Projet de Programmation, JUnit, retour sur le partiel. Infos pratiques. Rattrapage du 11/11 TD : lundi 16/11 Cours jusqu’au 2/12 Le projet a démarré : Il y a 6 séances Ne ratez pas les évaluations ! Les retards seront pénalisés.
E N D
Programmation Objet en JAVACours 8 : Projet de Programmation, JUnit, retour sur le partiel
Infos pratiques • Rattrapage du 11/11 • TD : lundi 16/11 • Cours jusqu’au 2/12 • Le projet a démarré : • Il y a 6 séances • Ne ratez pas les évaluations ! • Les retards seront pénalisés.
Agir avec méthode • Pour un développement conséquent, ne pas se perdre. • Les objectifs de base : • quels sont les objets nécessaires ? • quelles sont les interfaces de ces objets ? • existent-t-ils des classes ? Comment les écrire si nécessaire ? • Phase 0 : faire un plan ! • Phase 1 : définir l’objectif -> cahier des charges • Quel est le « produit » ? une application java • Faire des scénarii d’utilisation (use case) • Permet de répondre aux 3 questions de base. • Faire un fichier par classe, y écrire les signatures des méthodes publiques, et surtout beaucoup de commentaires. • Commencer l’écriture des interfaces qui répondent aux use cases. • Pas d’implémentation
Méthode - suite • Phase 2 : Comment construire ? Classes et interaction • Etendre la phase 1 et prévoir des classes utilisables et réutilisables. • Commencer l’écriture de chaque classe. • Bien choisir son nom. • Définir les responsabilités de chaque classe. • Définir les collaborations entre les classes. • Aboutir à un diagramme de classe • Un fichier source par classe, des classes courtes ! • Dans les commentaires, indiquer quelles sont les informations stockées et comment elles sont traitées. • Penser au polymorphisme.
Méthode - suite • Phase 3 : écrire le coeur de l’application • écrire les classes principales • « remplir » les fichiers, réaliser les commentaires. • implémentation, choix des attributs • encapsulation des données. • Tests unitaires • Phase 4 : Retour sur les scénarii utilisateur. • compléter, augmenter les use cases • Ajouter des classes et des méthodes • retour à la phase 2. • Phase 5 : évolution
Mise en oeuvre • Stratégies pour le code • Extreme programming : écrire d’abord les tests. • Pair programming • Divers : • n’oubliez les packages dans la conception. • Ne pas réinventer la roue, utiliser l’API Java, les conteneurs, ... • Documenter au maximum son code, pour l’utilisation et la réutilisation -> javadoc, vous travaillez à deux ! • L’utilisation de CVS (ou svn) est obligatoire • Voir sur le wiki de l’IE2, il existe un server svn paramétrable • Contacter Gilles Soufflet pour avoir un compte.
Pourquoi tester ? • Principe de programmation : un programme terminé est un programme testé ! • L’objectif est de garantir le fonctionnement d’un programme : • test formel : démontrer qu’un algorithme respecte un ensemble de spécification formel. • test exhaustif : envisager tous les cas possibles !!! • test heuristique : choisir judicieusement des cas d’utilisation critique.
Les différents types de test • test unitaire : • test les modules indépendamment • test d’intégration : • intégration des différents modules é • orienté utilisateur • test de régression : • s’assurer qu’une modification ne remet pas tout en cause. Les manières : • black box testing • vérification du respect par un objet de son interface, ses spécifications ⇒ test fonctionnel • white box testing • vérification des dé́tails d’une implémentation.
Problématique des tests unitaires • Cycle de développement « en TP » : • écriture d’un petit bout de code (quelques heures) • test avec le debugger ou avec des println. • vérification « à la main » des résultats • Le code ajouté au fur et à mesure est testé incrémentalement. • Mais : • peut-on ré-exécuter les tests ? non. • comment faire avec plus de 10 classes qui interagissent ? rien. • Comment visualiser tous les println ? • Peut mieux faire !
Principe des tests unitaires • Détecter les erreurs le plus tôt possible dans le cycle de développement : • tester la méthode dès son écriture • répéter l’ensemble des tests à chaque modification (régression) • garder la trace des résultats. • Les questions à se poser pour écrire un « bon test » : • la méthode fait-elle ce qui est attendu ? • supporte-t-elle les modifications d’autres méthodes ? • envisager des cas critiques d’utilisation. • Une approche extrême : • écrire les tests d’abord à partir du cahier des charges, coder ensuite !
Principe des tests unitaires - conséquences • Au moins un test par méthode ! • Le contenu d’un test : • fixture : code d’initialisation du test • assert : comparer la valeur attendue avec celle obtenue • un rapport (mail, gaphique, ...) • les tests sont indépendants. • Couverture : envisager le plus de cas possible • Conditions « au bord » • Répétition d’opération
Erreurs habituelles -> tests habituels • On a tendance a répéter les mêmes erreurs • faire des tests au plus tôt permet de réduire cet effet • Les erreurs habituels : • avec les nombres : 0, le plus grand/petit, positif/négatif, ... • avec des structures de données : • structure vide • avec un seul éléments • avec le maximum d’éléments • accès répéter à un même élément • duplication d’un élément • effacer un élément • ...
Selon les phases de travail • Phase de développement : • les tests qui doivent réussir : • test aux limites : trier une liste vide ou avec un seul élément • cas intéressant simple : trier une liste de deux valeurs • cas général : trier une liste de 11 valeurs • les tests qui doivent échouer : • entrée, accès invalides • mauvaise « entrée de l’utilisateur » • Phase de test : • dès qu’une anomalie est détectée : écrire le test qui correspond • documenter ses erreurs courantes.
Exemple chiffré Logiciel resolver (www. resolversystems.com) • 57k lignes de codes • 2 millions de dollars • 1 an et demi de développement pour 10 développeurs (10 lignes par jours) • 31k lignes de tests unitaires : 55%
JUnit 4 / Java > 1.4 • Un ensemble de test est regroupé dans une classe « normale » : • avec des attributs et des méthodes. • Les méthodes relatives aux tests utilisent les annotations : @Test public void methodeDeTest(){ .... } • Les annotations accrochent une information à une méthode, un attribut, ou une classe. • Cette information peut ensuite être traitée par un mécanisme indépendant (compilateur, interpréteur, environnement d’exécution, ... ). • Se créer et s’exécute avec un IDE. • Voir un exemple avec Eclipse : • création de la classe de test • exécution
JUnit4 - les assertions • static void assertTrue(boolean test) • méthode JUnit : vérifie (test == true) • dans le cas contraire lance une exception (en fait une Error) de type AssertionFailedError => traitée par l’exécuteur JUnit. • Les autres : • assertFalse • assertEquals • assertSame, sur les références • assertNotSame • assertNull, assertNotNull • fail : lance une erreur, avec un message.
Les « fixtures » et autres subtilités • Pour initialiser avant chaque test : @Before • Initialiser une seule fois : @BeforeClass • Pour après : @After, @AfterClass • Ignorer un test @Ignore • Tester dans un tempscontraint: @Test(timeout=1) • @Test(expected=IndexOutOfBoundsException.class) Pour plus d’information : • Le site junit.org • Un étude de cas : abreslav.googlepages.com/j-junit4-a4.pdf • Le site des furieux : extremeprogramming.org Pratiquer pendant le projet : • Les tests unitaires seront bienvenus !
Projet de programmation • Introduction
Un projet de développement (objet) Les 5 phases fondamentales • Analyse du problème • Conception objet • Implémentation • Test et vérification • Documentation • Ces 5 phases sont d’égales importances. • Le projet se fait en binôme.
Les objectifs du projet • réaliser entièrement, de zéro, un projet à partir de spécifications informelles (énoncé en français) et formelles (un ensemble d'interfaces); • étape de conception préalable à l'implémentation; • encapsuler vos données pour obtenir des programmes robustes; • éprouver l'intérêt de séparer la partie traitement d'un programme de sa partie interface utilisateur; • tester au fur et à mesure ! • des programmes réutilisables par d’autres et par vous; donc les écrire lisiblement en les commentant judicieusement; • utiliser javadoc pour générer la documentation • utiliser des outils développements appropriés.
Le sujet, le jeu • Parcourir l’Ardèche en passant par un maximum de villages différents • Mais à chaque route son moyen de transport.
Les éléments de Jeu • Les joueurs (un nom, une couleur) • La carte de l’Ardèche : 20 villages reliés par 36 routes • Une route relie 2 villages et traverse un type de paysage parmi 4 : • plaine, forêt, garrigue, montage • le type de la route implique des moyens de transport et des coûts spécifiques. • Un carte moyen de transport = un crédit pour un mode de transport : • l'âne, le sanglier, le vélo, le tracteur, la mobylette, et l'ULM • Un pion de transport : • permet d’indiquer pour une route de la carte quel moyen de transport DOIT être utilisé. • un seul pion par route (hors obstacle)
Tour de jeu : 6 étapes • Etape 1 : distribution des cartes Voyage (8 par joueur) • Les cartes doivent donc être distribuée aléatoirement • Créer toutes les cartes, et les ranger dans un paquet • Prévoir une méthode pour distribuer les cartes (une à une, ou n fois) • Un joueur doit pouvoir « contenir » ses cartes • Etape 2 : Attribution du pion de transport caché • Chaque joueur reçoit un pion de transport que lui seul connait, pris dans le paquet des pions de transport. • Comme pour les cartes et le paquet de cartes • Un joueur doit connaître son pion caché, mais pas les autres joueurs.
Tour de jeu - suite • Etape 3 : Attribution des pions de transport • Parmi le paquet de pions de transport, 5 pions sont au préalable piochés et posés face visible • Chaque à tour de rôle joueur a le choix : • prendre un des 5 pions visibles, dans ce cas le pion pris est remplacé • ou piocher dans le paquet. • Au total, chaque joueur doit acquérir 3 pions de cette manière. • Ces trois pions sont visibles des autres joueurs.
Tour de jeu - encore • Etape 4 : préparation des routes • chacun son tour, un joueur pose un pion de transport sur une route • Sur une route, il ne peut y avoir qu'un seul pion moyen de transport. • Un moyen de transport ne peut être posé sur une route que s'il est approprié • Ces moyens de transportposés sur le plateau peuvent être utilisés par tous les joueurs lors de leurs déplacements (phase suivante). • Au lieu d’un pion moyen de transport, un joueur peut placer un obstacle. • Sur un moyen de transport déjà en place. Sur une route il ne peut y avoir qu'un obstacle. • Un obstacle sur une route oblige à payer plus cher. • Un joueur peut aussi passer son tour. • Si aucun joueur ne veut ou ne peut plus poser de moyen de transport, cette phase est terminée.
Tour de jeu - encore • Etape 5 : le voyage • chacun son tour, le joueur se déplace sur les routes où sont posés les pions de transport • en payant avec ses cartes de transport, • sur autant de routes qu'il veut et en visitant autant de villages qu'il peut en respectant les règles. • Le but : atteindre des villes différentes. • Premier passage dans une ville, le joueur prend un pion/marqueur de sa couleur. • Une ville doit donc contenir un marqueur par joueur ! on peut l’enlever une fois, c’est tout.
Tour de jeu - c’est presque fini • Etape 6 : résolution du tour • Le rôle de premier joueur passe au suivant. • Chaque joueur doit redonner tous ses pions moyen de transport pour n'en garder qu'un seul (caché ou visible). • Les obstacles utilisés sont retirés du jeu définitivement. • Toutes les cartes Voyage qui ont été jouées ou défaussées sont remises dans le paquet de cartes • Il y a 4 tours de jeu !
Représentation du plateau • Pas besoin d’être réaliste • Obligatoire : • 20 villes, 36 routes • des idées dans le sujet • Comment coder une carte ? • une Ville ? • un nom • une ville doit-elle connaître ses routes ? • Un marqueur par joueur, ... • une route ? • un type • deux villes • un pion adapté, un obstacle, ...
Conception du moteur (l’IG, connait pas) • Lister les classes, écrire pour chacune son interface • Choisir ses packages • Ecrire le main d’un tour de jeu • ici les 6 phases • chaque phases peut manipuler les interfaces Joueur, Ville, Pion, ... . • Faire des schémas d’utilisation et des diagrammes de classes !
Exemple de l’étape 1 : distribution des cartes • Une classe Carte ? • Comment lier le type des routes, le type des pions transport et le type des cartes ? • Comment faire pour qu’une carte Voyage puisse s’utiliser sur une route ayant un certain pion de transport ? • Une route avec un pion de transport ne pourra être empruntée par un joueur qu’avec une carte adaptée ! • Le joueur transmet une liste de carte ? • Comment traiter les Exceptions ? • Une classe Paquet de Carte : • contient au plus 72 cartes => un tableau • répartition des types de cartes => constructeur • une interface pour les constantes ? Une classe Config ? • méthode shuffle (mélange les cartes) • méthode distribution(Joueur j, int nbCartes) • Que renvoie-t-elle ? • Exception ?
Autre exemple de use case • Le joueur veut déplacer son pion : • comment caractériser le déplacement ? le choix de la voie est mieux que le choix de la destination (plusieurs voies possibles) • Le paramètre de la méthode peut être une voie de transport. • Il faut alors vérifier que le joueur peut effectuer ce déplacement : • qui le fait ? le joueur, la voie ? • Prévoir par exemple un « type » voie avec une méthode • public int empruntablePar(Joueur j) • Cette méthode doit avoir accès à la position et les cartes du joueur => getters • On peut contraindre le choix du joueur en lui passant toutes les voies empruntables (pratique pour le moteur et pour l’IG).