geraldcroes/yagni — pull request #2 by jubianchi (2014-04-02 20:07:19+00:00)
Title: Add a new tarification for real babies (< 2 yo)

Pour faire suite à nos discussions, voici une nouvelle PR dans laquelle j'étends la classe `YagniTicketTarification` car **les tranches d'age qu'elle utilise ne me conviennent pas/plus** : pour moi, **un bébé n'en est plus un à partir de deux ans**. Il sait (normalement) marcher, parler, ... c'est donc devenu un enfant :)

Bref, j'étend donc cette classe en redéfinissant la méthode protected qui va bien, à savoir la méthode `isConsideredABaby`.

Le "problème", c'est qu'en réalité, **je n'ai pas cassé le contrat de la classe** `YagniTicketTarification` qui, par sa seule méthode publique, va toujours me retourner un flottant représentant le prix d'un ticket pour une personne donnée.

Je n'ai pas cassé son contrat, par contre, **j'a largement modifié son comportement**. Et bien que le contrat soit toujours respecté, la méthode ne se comporte plus du tout de la manière (bon j'exagère un peu là :wink:).

Je dois donc figer le nouveau comportement au niveau des tests unitaires associés à cette nouvelle classe.

Comme je travail en TDD et qu'à priori, je ne sais pas trop ce qui est à ma disposition dans le code pour créer le nouveau comportement, je vais commencer par mettre un test au niveau de la méthode publique de la classe que je vais écrire : j'ai une interface à respecter, je sais donc avec certitude par où commencer.

En travaillant de cette manière, qu'est ce qui se passe :

* Une grande partie du **test unitaire de la classe mère est dupliqué**
* Dans le nouveau test unitaire, **je modifie uniquement les données fournies par le provider pour coller à ce que je souhaite implémenter**
* **je test toujours totalement** mes *protected* à travers la méthode publique
* je fige/spécifie/définis/test le comportement que je veux implémenter
* **j'assure que le reste fonctionne toujours de la même manière**
* **je reste le plus loin possible des détails d'implémentation** interne de la classe (à savoir les *protected*)

La seule chose ici qui, pour moi, pourrait poser problème est la duplication de code au niveau du test, mais est-ce réellement un problème dans les tests si je peux garantir que *mon code est toujours bien couvert*, que lui *ne contient pas de duplication*, qu'il est propre et surtout, qu'il *fait le travail demandé* ?

D'autre part, **si demain je souhaite déléguer la logique de vérification de l'age à un autre composant, mon test ne bougera pas**. Oui je sais, il ne faut pas penser à demain, désolé, je ne peux pas m'en empêcher :laughing:.

Voilà le genre de cas qui me fait dire que tester les *protected* n'est pas forcément nécessaire. Elles sont là pour supporter les méthodes publiques, j'ai donc toujours un point d'entrée pour atteindre leur code, le stresser, et vérifier les retours.

Imaginons maintenant que j'ai pu tester les *protected* : peut-être que j'aurais eu tendance à vérifier uniquement le retour booléen de la méthode `isConsideredABaby` car c'est la seule chose que ma novuelle classe contient. Or, si j'avais travaillé de cette manière, j'aurais peut-être loupé le fait que ma modification n'était pas suffisante.

En effet, pour que tout fonctionne, **j'ai également du légèrement modifier la méthode `isConsideredAChild` de la classe mère** pour que celle-ci s'adapte à la nouvelle borne de ma tranche.

Je préfère donc dupliquer du code dans les tests et **TOUJOURS** couvrir l'interface publique, même si je ne modifie que l'implémentation interne et masquée de la classe. Je garantis ainsi que le service attendu est toujours bien rendu, au niveau des nouvelles règles mais également au niveau des règles que je n'ai pas touchées.