Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

L'Arene — correction

Correction du brief L'Arene. Trois ecoles de combat (Guerrier, Mage, Archer) creent des combattants dont chaque statistique est choisie dans les bornes de son ecole, puis on les fait s'affronter.

Organisation des branches

Chaque etape du brief a sa branche :

Branche Contenu
main = correction/etape-1
correction/etape-1 hierarchie, validation des bornes, getInformation(), tests de construction
correction/etape-2 specialAbility(), feat(), modifier(), power()
correction/etape-3 Ranking, FightManager.fight1v1
correction/etape-4 Element et le cycle des affinites
correction/etape-5 fightContest, version boucles et version streams

Structure du code

src/
  Main.java              cree un combattant de chaque ecole et les affiche
  main/
    Fighter.java         classe mere abstraite : nom, hp, strength, speed
    Warrior.java         hp 96-106, strength 20-24, speed 8-12, rage 12-18
    Mage.java            hp 88-98,  strength 14-18, speed 18-22, mana 32-48
    Archer.java          hp 90-100, strength 17-21, speed 21-25, precision 20-30
  test/
    WarriorTest.java     construction valide + refus de chaque borne
    MageTest.java
    ArcherTest.java

Ou vit quoi, et pourquoi :

  • Dans Fighter : ce qui est identique pour les trois ecoles — les trois statistiques de base et leurs getters, le helper validateAttribute, et getInformation().
  • Dans chaque ecole : ses bornes (constantes HP_MIN, HP_MAX...), son attribut propre avec son getter, et la redefinition de getInformation() qui ajoute cet attribut a la description commune.

Combattants de reference

Les trois combattants du brief, utilises tels quels dans les tests :

Combattant Statistiques
Warrior « Bjorn » hp 100, strength 22, speed 10, rage 15
Mage « Lyra » hp 90, strength 16, speed 20, mana 40
Archer « Sylve » hp 95, strength 19, speed 23, precision 25

A retenir

1. Compiler n'est pas executer

Ce sont deux moments distincts, et confondre les deux fait perdre beaucoup de temps en debogage.

Une erreur de compilation empeche le programme d'exister. Le compilateur refuse de traduire votre code, il n'y a donc rien a lancer : pas une seule ligne ne s'execute, meme celles qui etaient parfaitement correctes. Un point-virgule oublie, une methode appelee qui n'existe pas, un type qui ne correspond pas : le projet ne compile pas, point.

Une exception, elle, arrive a l'execution. Le code etait valide, il a compile, le programme a demarre, et il s'interrompt en cours de route. C'est exactement le cas du Warrior cree avec hp = 500 : ce code est parfaitement correct du point de vue du compilateur — 500 est bien un int, le constructeur existe et attend bien un int. C'est seulement pendant l'execution, au moment ou la valeur est reellement testee contre les bornes, que le throw part.

Comment les distinguer en pratique : une erreur de compilation est signalee avant que vous n'ayez lance quoi que ce soit (souligne en rouge dans IntelliJ, le bouton Run echoue tout de suite). Une exception s'affiche pendant l'execution, sous forme de trace de pile dans la console, apres que les lignes precedentes se sont deja executees et ont deja affiche leur resultat.

2. Le casse-tete de assertThrows

assertThrows fonctionne a l'envers de toutes les autres assertions, et c'est le piege numero un de cette etape.

  • assertEquals(100, bjorn.getHp()) : vert si le code donne le bon resultat.
  • assertThrows(IllegalArgumentException.class, () -> new Warrior(...)) : vert si le code echoue.

Autrement dit : le test est OK si le code est KO, et KO si le code est OK. Un test hpTooLowThrows qui passe au rouge ne veut pas dire « le constructeur a plante », il veut dire l'inverse : le constructeur a accepte une valeur qu'il aurait du refuser.

3. Comment verifier que la bonne exception est levée

assertThrows verifie seulement qu'une exception du bon type a ete levee. Il ne dit pas laquelle. Avec quatre attributs a valider et huit tests de bornes par ecole, c'est vite ingerable : un test cense verifier que hp est refuse peut passer au vert parce que c'est la validation de speed qui a leve (un erreur de copier coller est vite arrivée). Le test est vert, il ne teste pas ce qu'on croit, et il resterait vert meme si la validation de hp disparaissait completement. D'ou l'assertion supplementaire sur le message :

IllegalArgumentException error = assertThrows(IllegalArgumentException.class,
        () -> new Warrior("Bjorn", 95, 22, 10, 15));
assertTrue(error.getMessage().contains("hp"));

On ne verifie plus seulement qu'il y a eu une erreur, mais qu'on est bien tombe sur la bonne. C'est aussi ce qui justifie de construire le message a partir du nom de l'attribut dans validateAttribute : sans message parlant, il n'y a rien a assertionner.

4. Ne pas oublier les getters

Les attributs d'un objet doivent etre prives : private final int hp;. C'est l'encapsulation — personne ne peut les lire ni les modifier directement depuis l'exterieur de la classe.

La consequence est tres concrete : sans getter, votre objet est une boite noire. Les tests ne peuvent rien verifier et on ne peut pas réccupèrer les valeur ailleurs que dans leurs propre classe. C'est pour ca que constructsWithValidValues a besoin de getName(), getHp(), getStrength(), getSpeed() et du getter de l'attribut propre.

Ou les placer suit la meme logique que le reste :

  • dans Fighter, les getters des attributs communs (getName, getHp, getStrength, getSpeed) ;
  • dans chaque ecole, le getter de son attribut propre (getRage, getMana, getPrecision), parce que cet attribut n'existe que la.

5. super(...) s'execute avant votre validation

L'appel au constructeur de la classe mere passe toujours en premier, c'est impose par Java. Les champs sont donc bien affectes, puis la validation leve.

L'objet a moitie initialise a bien existe une fraction de seconde. Mais comme le constructeur ne se termine jamais, aucune reference n'est rendue a l'appelant : la variable n'est jamais affectee, et le ramasse-miettes recupere l'objet. Du point de vue du programme, ce combattant invalide n'a jamais existe.

C'est la question de reflexion de cette etape, detaillee dans REFLEXION.md.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages