Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
ens:cvda2016:tpbiblio [2016/05/17 06:30]
admin Cordier Amelie () [Contexte]
ens:cvda2016:tpbiblio [2016/05/29 13:54] (Version actuelle)
admin Cordier Amelie ()
Ligne 15: Ligne 15:
   * Appréhender le concept de programmation dirigée par les tests (TDD, Test Driven Development).    * Appréhender le concept de programmation dirigée par les tests (TDD, Test Driven Development). 
   * En bonus : utiliser Git.    * En bonus : utiliser Git. 
 +
 +<WRAP center round tip 60%>
 +Ce n'est pas obligatoire mais... ce serait une bonne idée que vous utilisiez un gestionnaire de versions tel que Git pour enregistrer les différentes étapes de votre projet... Rappelez-vous que c'est en vous entraînant que vous vous familiariserez le mieux avec ce type d'outils. Ce TP est l'occasion idéale de s'entraîner sans risque !
 +</WRAP>
  
 ===== Partie 1. Création de la classe Personne ===== ===== Partie 1. Création de la classe Personne =====
Ligne 33: Ligne 37:
   * Suggestions d'implémentation : Netbeans propose de définir comme ''Final'' certaines variables. Pourquoi ?     * Suggestions d'implémentation : Netbeans propose de définir comme ''Final'' certaines variables. Pourquoi ?  
 </note> </note>
 +
 +{{ :ens:cvda2016:personneuml.png?200 |}}
  
 3. Créez une classe de test pour la classe ''Personne.java''. Vous pouvez choisir d'utiliser les fonctionnalités de génération automatique, ou bien  3. Créez une classe de test pour la classe ''Personne.java''. Vous pouvez choisir d'utiliser les fonctionnalités de génération automatique, ou bien 
 le faire à la main, mais dans tous les cas, prenez bien garde à séparer le code de test du code métier. Le contenu de votre classe de test  le faire à la main, mais dans tous les cas, prenez bien garde à séparer le code de test du code métier. Le contenu de votre classe de test 
 doit être le suivant. Notez que pour l'instant, on ne se préoccupe pas de la gestion du numéro de personne. **Exécutez les tests et observer qu'aucun d'eux ne passe.**  doit être le suivant. Notez que pour l'instant, on ne se préoccupe pas de la gestion du numéro de personne. **Exécutez les tests et observer qu'aucun d'eux ne passe.** 
 +
 +<note important>Si, au moment de l'exécution, votre projet contient des erreurs, c'est que vous avez manqué une étape. Corrigez les erreurs avant d'aller plus loin.</note>
   
 <file java PersonneTest.java> <file java PersonneTest.java>
Ligne 169: Ligne 177:
  
 4. Implémentez les méthodes de la classe Personne de sorte à ce que tous les tests (sauf les deux tests relatifs à la gestion des numéros).  4. Implémentez les méthodes de la classe Personne de sorte à ce que tous les tests (sauf les deux tests relatifs à la gestion des numéros). 
-Ajoutez l'annotation @Ignore pour ignorer ces deux tests. Observez :+ 
 +<note tip>Ajoutez l'annotation ''@Ignore'' pour ignorer les deux tests que l'on ne souhaite pas gérer tout de suite. Observez :
  - Comment gérer l'import nécessaire ?   - Comment gérer l'import nécessaire ? 
  - Quel est l'impact de @Ignore sur le résultat de l'évaluation des tests ?   - Quel est l'impact de @Ignore sur le résultat de l'évaluation des tests ? 
 +</note>
  
 5. Nous allons maintenant traiter le cas du numéro de personne.  5. Nous allons maintenant traiter le cas du numéro de personne. 
   * Quelles sont les différentes stratégies pour gérer le numéro de personne ? Quels sont les avantages et les inconvénients de chacune ?    * Quelles sont les différentes stratégies pour gérer le numéro de personne ? Quels sont les avantages et les inconvénients de chacune ? 
-  * Ecrivez les tests permettant de vérifier le bon fonctionnement de l'affectation des numéros de personne. +  * Concevez et écrivez les tests permettant de vérifier le bon fonctionnement de l'affectation des numéros de personne. 
   * Implémentez les méthodes correspondantes   * Implémentez les méthodes correspondantes
   * Mettez à jour la méthode toString() de Personne pour afficher les n° de personne, et mettez également à jour le test correspondant.    * Mettez à jour la méthode toString() de Personne pour afficher les n° de personne, et mettez également à jour le test correspondant. 
  
-Attention : dans le corrigé proposé, la solution retenue n'est pas conforme aux spécifications initiales du sujet ! La méthode "getDernierNumn'existe plus. +<note warning>Attention : dans le corrigé proposé (code sur Githubà partir du commit 3071905) la solution retenue n'est pas conforme aux spécifications initiales du sujet ! La méthode ''getDernierNum()'' n'existe plus. De plus, la méthode ''setNumPers()'' est remplacée par un ''getNextNumPers()'' utilisé uniquement dans le constructeur de ''Personne''. Notez enfin que cette dernière méthode est privée, de sorte à éviter les mauvais usages
-De plus, la méthode "setNumPersest remplacée par "getNextNumPers". Notez enfin que cette dernière méthode est privée, de sorte à éviter les mauvais usages+
 liés à la gestion des numéros de personnes. C'est un choix d'implémentation. D'autres solutions auraient été possibles.  liés à la gestion des numéros de personnes. C'est un choix d'implémentation. D'autres solutions auraient été possibles. 
 +</note>
 +
 +====== Partie 2. Gestion d'une liste de personnes =====
 +
 +6. Créez une nouvelle classe ''ListePersonnes.java'' dont la mission sera de gérer une liste de ''Personne''. Comme dans la question 2, n'implémentez pas les méthodes. Contentez-vous d'écrire un squelette fonctionnel. La classe doit contenir un constructeur, une méthode ajouter qui permet d'ajouter une personne à la liste, et une méthode appartient, qui permet de vérifier qu'une personne appartient bien à la liste. 
 +
 +<note tip>
 +On peut légitimement se demander comment implémenter la méthode "appartient". En effet, soit on considère que l'on doit vérifier si une ''Personne p'' appartient à la liste, ce qui est trivial à implémenter, mais pas forcément très utile dans la pratique, soit on considère que le problème est de savoir si une personne dont on connaît le nom et le prénom appartient à la liste... Ce deuxième cas est un peu plus difficile, mais c'est probablement ce qui va intéresser les utilisateurs de notre méthode ! Faites donc les deux !</note>
 +
 +7. Cette fois-ci, c'est votre tour d'écrire les tests de cette classe. Générez la classe de test (manuellement, ou automatiquement, à votre convenance). Si vous la générez manuellement, observez qu'il est parfois nécessaire de modifier le code automatiquement généré ;) 
 +Une fois que vous avez fini d'écrire les tests, vérifiez qu'ils fonctionnent et qu'ils échouent (puisque le code métier n'est pas encore écrit). 
 +
 +8. Complétez maintenant votre classe ''ListePersonnes'' pour qu'elle passe les tests. 
 +
 +9. Il est temps de générer la **javadoc** pour vous assurer que le processus fonctionne correctement. Vous <del>pourrez</del> devrez toujours la mettre à jour plus tard. Que se passe-t-il pour les tests ? Est-ce qu'une javadoc est générée ? 
 +====== Partie 3. Refactoring ======
 +
 +10. Ne trouvez vous pas qu'il est fastidieux de recréer les personnes et les listes de personnes à chaque test ? Nous allons donc utiliser les outils proposés par JUnit (méthodes de ''setUp'') pour remédier à cela. Refactorez tout le code que vous avez écrit jusqu'ici en utilisant les méthodes de ''setUp''. Ensuite, exécutez à nouveau l'ensemble de vos tests pour vérifier que vous n'avez rien cassé. 
 +
 +<note tip>Le **refactoring** consiste à ré-organiser du code de façon à le rendre plus "propre". C'est une étape normale du développement d'un programme : au fur et à mesure de l'avancement, nous avons les idées plus claires sur ce que nous voulons, et donc nos envies d'organisation évoluent. **Il ne faut pas hésiter à refactorer souvent !**. Si les tests unitaires sont bien faits, ils vous permettront de vérifier que le refactoring que vous avez fait ne "casse pas" votre code.</note>
 +
 +<note tip>L'outil **refactor** de Netbeans permet de rechercher et remplacer le nom d'une variable / d'une méthode dans tout votre code. C'est un outil très utile dans le contexte du refactoring car il est plus performant qu'un simple "rechercher/remplacer" : il remplace toutes les occurrences de la variable ou de la méthode dans tout le code... et non l'occurrence de la chaîne de caractères. N'hésitez pas à tester cet outil pour mieux en comprendre le fonctionnement.</note>
 +
 +====== Partie 4. Génération de code ======
 +
 +11. Nous allons maintenant nous occuper de la classe ''Livre.java''. Comme pour la classe ''Personne.java'', c'est à vous d'écrire le squelette de la méthode selon les spécifications. N'avez-vous pas trouvé fastidieux le fait de devoir écrire la classe ''Personne.java'' la première fois ? N'auriez-vous pas préféré pouvoir générer le code automatiquement à partir du diagramme UML ? Et bien figurez-vous que c'est possible. 
 +
 +Vous trouverez {{:ens:cvda2016:livre.zip|ici}} un fichier que vous pouvez ouvrir avec ArgoUML après l'avoir extrait. Il contient le diagramme de classe contenant uniquement la classe Livre. 
 +
 +  * Ouvrez le fichier avec ArgoUML. 
 +  * Explorez le projet pour afficher la classe ''Livre'' dans l'interface principale. 
 +  * Si la classe apparaît comme vide, cliquez (bouton droit) dessus, et choisissez d'afficher tous les champs.
 +  * Cherchez comment générer du code Java directement à partir de ce diagramme de classes. Magique non ? Imaginez le temps que vous pourriez gagner sur un projet contenant plusieurs dizaines de classes et plusieurs packages !
 +
 +12. Il est temps de finir la classe ''Livre''. Récupérez la classe de test ci-dessous, complétez-là si vous le jugez utile, puis implémentez la classe livre de sorte à ce que tous les tests passent. 
 +
 +<file java LivreTest.java>
 +/**
 + * Bibliothèque
 + * TP CVDA 2016 - Amélie Cordier
 + */
 +package bibliotheque;
 +
 +import org.junit.After;
 +import org.junit.AfterClass;
 +import org.junit.Before;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +import static org.junit.Assert.*;
 +
 +
 +/**
 + * Classe LivreTest
 + * @author Amélie Cordier - IUT Lyon 1
 + * @version 1.0
 + * mai 2016
 + */
 +public class LivreTest {
 +    
 +    static Personne alan;
 +    static Livre computing;
 +    
 +    /**
 +     *
 +     */
 +    public LivreTest() {
 +    }
 +    
 +    /**
 +     * Création d'une personne et d'un livre à l'initialisation des tests.
 +     * Ces éléments ne seront pas modifiées par la suite. 
 +     */
 +    @BeforeClass
 +    public static void setUpClass() {
 +        alan = new Personne("Turing", "Alan", 1912);
 +        computing = new Livre("Computing Machinery and Intelligence", 250, alan);
 +    }
 +    
 +    /**
 +     *
 +     */
 +    @AfterClass
 +    public static void tearDownClass() {
 +    }
 +    
 +    /**
 +     *
 +     */
 +    @Before
 +    public void setUp() {
 +    }
 +    
 +    /**
 +     *
 +     */
 +    @After
 +    public void tearDown() {
 +    }
 +
 +    /**
 +     * Test de getNumLivre de la classe Livre.
 +     */
 +    @Test
 +    public void testGetNumLivre() {
 +        assertEquals(0, computing.getNumLivre());
 +    }
 +
 +    /**
 +     * Test de getNumLivre de la classe Livre.
 +     */
 +    @Test
 +    public void testGetNumLivreTwoBooks() {
 +        Livre mind = new Livre("mind", 0, alan);
 +        Livre mind2 = new Livre("mind2", 0, alan);
 +        assertEquals(mind.getNumLivre()+1, mind2.getNumLivre());
 +    }
 +
 +    /**
 +     * Test de getTitre de la classe Livre.
 +     */
 +    @Test
 +    public void testGetTitre() {
 +        String titreAttendu = "Computing Machinery and Intelligence";
 +        assertTrue(computing.getTitre().equals(titreAttendu));
 +    }
 +
 +    /**
 +     * Test de getNombreDePages de la classe Livre.
 +     */
 +    @Test
 +    public void testGetNombreDePages() {
 +        assertEquals(250, computing.getNombreDePages());
 +    }
 +
 +    /**
 +     * Test de getAuteur de la classe Livre.
 +     */
 +    @Test
 +    public void testGetAuteur() {
 +        assertEquals(alan, computing.getAuteur());
 +    }
 +
 +    /**
 +     * Test de setTitre de la classe Livre.
 +     */
 +    @Test
 +    public void testSetTitre() {
 +        Livre mind = new Livre("?", 0, alan);
 +        mind.setTitre("Mind");
 +        assertTrue(mind.getTitre().equals("Mind"));
 +    }
 +
 +    /**
 +     * Test de setAuteur de la classe Livre.
 +     */
 +    @Test
 +    public void testSetAuteur() {
 +        Livre ged = new Livre("?", 0, alan);
 +        Personne douglas = new Personne("Hofstadter", "Douglas", 1945);  
 +        ged.setAuteur(douglas);
 +        assertTrue(ged.getAuteur().equals(douglas));
 +    }
 +
 +    /**
 +     * Test de setNombreDePages de la classe Livre.
 +     */
 +    @Test
 +    public void testSetNombreDePages() {
 +        Livre mind = new Livre("?", 0, alan);
 +        mind.setNombreDePages(500);
 +        assertEquals(500, mind.getNombreDePages());
 +    }
 +
 +    /**
 +     * Test de toString de la classe Livre.
 +     */
 +    @Test
 +    public void testToString() {
 +        String expStr = "Computing Machinery and Intelligence, Alan Turing, 250p.";
 +        assertTrue(computing.toString().equals(expStr));
 +    }
 +}
 +    
 +</file>
 +====== Partie 5. La pause s'impose  ======
 +
 +Dans la prochaine partie, vous allez passer à la gestion de la bibliothèque.
 +Avant cela, il est nécessaire de prendre un peu de recul sur ce que vous avez fait, de vérifier que tout est codé correctement, etc.
 +Prenez donc quelques minutes pour : 
 +  * Vérifier que les parties cruciales de votre code sont commentées correctement
 +  * Vérifier que la Javadoc de ce qui est implémenté est correcte et complète
 +  * Vérifier que vous n'avez pas oublié des tests importants
 +  * Vérifier que vous respectez bien les bonnes pratiques de programmation (pensez au "refactor" et au "format"), dont
 +    * l'indentation correcte du code 
 +    * le respect des conventions de nommage des variables 
 +    * le non "mixage" du français et de l'anglais dans votre code  
 +  * Vérifier que tous les tests passent, après les avoir refactorés au besoin
 +  * Faire un commit de cette version "stable" de votre projet. 
 +
 +<note tip>Notez que nous ferons un cours sur les bonnes pratiques de programmation... ce petit exercice n'est qu'un avant-goût !</note>
 +
 +** Couverture des tests **
 +
 +Pour évaluer la qualité de vos tests, vous pouvez également analyser la couverture des tests. Il existe de nombreux outils indépendants pour faire cela (Jenkins, Sonar, etc.), mais ici, pour rester simples et efficaces, nous allons utiliser un plugin de Netbeans. 
 +
 +La première fois, il est nécessaire d'installer le plugin. Pour cela, aller dans ''Tools > Plugins'' et cherchez le plugin "JaCoCoverage". Sélectionnez-le et installez-le. Vous pouvez en profiter pour faire la mise à jour des plugins de Netbeans. 
 +
 +Une fois le plugin installé et Netbeans redémarré, cliquez (bouton droit) sur le projet et faites un Test avec JaCoCoverage. Observez le résultat. Que pouvez-vous en déduire sur la qualité de vos tests ? 
 +
 +====== Partie 6. Gestion de la bibliothèque  ======
 +
 +Passez maintenant à l'implémentation de la bibliothèque selon la méthode que vous préférez. 
 +Pour mémoire : une bibliothèque est une structure dans laquelle on peut mettre des livres. 
 +La classe ''Bibliotheque'' doit proposer des méthodes pour ajouter un livre, afficher le contenu
 +de la bibliothèque, rechercher par auteur, et rechercher par titre. Vous devez gérer les exceptions
 +pour ces deux derniers cas (i.e. quand le livre n'est pas trouvé). 
 +
 +Essayez d'adopter une démarche TDD pour réaliser cette partie : 
 +  * Création du squelette de la classe
 +  * Écriture des tests unitaires
 +  * Complétion de la classe
 +  * Exécution des tests
 +  * Refactoring jusqu'à ce que la classe soit complète et fonctionnelle
 +
 +<note important>Pensez bien à documenter votre code !</note>
 +
 +====== Partie 7. Finalisation du projet  ======
 +
 +A nouveau, prenez le temps d'inspecter votre code, de vérifier qu'il est bien formaté et bien documenté.
 +Refactorez ce qui nécessite de l'être et vérifiez grâce aux tests que vous n'avez rien cassé. 
 +Vérifiez la couverture de vos tests. 
  
-Partie 2. Gestion d'une liste de personnes +Lorsque vous aurez terminé votre projet, il ne vous restera plus qu'à mettre à jour quelques éléments :  
 +  * La Javadoc, pour prendre en compte toutes les nouvelles améliorations que vous avez apportées 
 +  * Le diagramme de classe du projet, car il a nécessairement changé un peu depuis la conception initiale
  
-Créez une nouvelle classe "ListePersonnes" dont la mission sera de gérer une liste de Personnes. Comme dans la question 2 : n'implémentez pas les méthodes. Contentez-vous d'écrire un squelette fonctionnel+De plus, si vous ne l'avez pas encore fait, il est probablement temps de pousser votre historique de commits sur un dépôt distant
  
-Cette fois-ci, c'est votre tour d'écrire les tests de cette classe. Générez la classe de test (manuellement, ou automatiquement, à votre convenance).  
-Si vous la générez manuellement, observez qu'il est parfois nécessaire de modifier le code automatiquement généré ;) 
  
-Il n'y a pas trop lieu de tester afficherAppartenance