Episode 3, saison 1.
- utilisation des outils de test et debuggage
- écriture et test d'une Collection: partie 1 , puis partie 2 (ce billet)
- utilisation des Traits dans les tests unitaires
Inspector Thomas D. Derrick was facing Mister M., a supposed movies dealer. He had to find the truth. What did Mister M. do with the movies ?
- Where do you put the movies ? T.D.Derrick asked.
- I'm a Collection. I keep them.
- You're a Collection, aren't you ? So what's your size ?
- Well ... Zero now. I'm empty !!
- I'm sure you lie. Take this movie ... "Star Wars". Take it !
- OK OK, done.
- And tell me what's your size now ...
- One. You see, I have it.
These right answers did not disturbed T.D.Derrick.
- Play again with me. Add these movies. "Blade Runner" and ... this one, "Alien".
- Done.
- And now, your size ?
- Three. Can I go now ?
Mister M. seemed to be a real Collection. T.D.Derrick felt he was missing something. Then a subtil smile appeared on his face:
- Do you include Star Wars ?
- Err ... hard to tell. I don't understand.
- What ?
- I don't understand "include"
- Yep, I got you now !!
- Damned ...
Au dernier billet, j'ai décrit l'implémentation, pilotée par les tests, de la méthode Movies#size. La méthode retourne le nombre de films ajoutés via Movies#add.
Déclarons moviesCollection comme variable d'instance pour la rendre accessible aux autres méthodes de la classe Movies.
2.1 movies, starWars, bladeRunner et alien
Supprimons les duplications. Avant toute chose, vérifions que tous les tests de notre package Movies passent.
TestCase propose les méthodes setUp et tearDown pour ce genre de situation. TestCase#setUp est exécutée avant chaque test, et tearDown aprés chaque test. Lorsqu'on exécute tous les tests de MoviesSizeTest, l'appel des méthodes est le suivant (à l'ordre des tests près):
2.2 Renommer MoviesSizeTest
Le nom de la classe ne reflète plus assez la totalité des tests, car on vérifie les retours des méthodes Movies#size et Movies#includes. Le vrai objectif est de s'assurer que Movies#add ajoute bien les instances de Movie. Renommons la classe en MoviesAddMovieTest.
2.3 Supprimer le comteur size de Movies
Regardons Movies#add de nouveau:
moviesCollection est une instance d'OrderedCollection.
OrderedCollection#size retourne le nombre d'instance stockées. On peut donc supprimer le compteur size qui fait doublon.
Relancez les tests:
Oups ... On s'aperçoit via le debugger que Movies#size retourne toujours 0.
L'erreur saute aux yeux en ouvrant Movies#size:
Corrigeons la méthode:
et les tests repassent !
Nettoyons au passage Movies#initialize pour supprimer l'initialisation de size:
et nous pouvons finalement supprimer size des variables d'instances de Movies:
3. Pause publicité
Notre collection est minimale mais testée. Comme pour les billets précédents, nous écrivons d'abord le test puis nous nous laissons guider par les erreurs et le debugger pour implémenter le code fonctionnel.
Après chaque test, on modifie le code testé et de test pour l'améliorer.
La prochaine fois, nous retravaillerons MoviesAddMovieTest mais en utilisant les Traits, un mécanisme de réutilisation de code entre classes.
- Where do you put the movies ? T.D.Derrick asked.
- I'm a Collection. I keep them.
- You're a Collection, aren't you ? So what's your size ?
- Well ... Zero now. I'm empty !!
- I'm sure you lie. Take this movie ... "Star Wars". Take it !
- OK OK, done.
- And tell me what's your size now ...
- One. You see, I have it.
These right answers did not disturbed T.D.Derrick.
- Play again with me. Add these movies. "Blade Runner" and ... this one, "Alien".
- Done.
- And now, your size ?
- Three. Can I go now ?
Mister M. seemed to be a real Collection. T.D.Derrick felt he was missing something. Then a subtil smile appeared on his face:
- Do you include Star Wars ?
- Err ... hard to tell. I don't understand.
- What ?
- I don't understand "include"
- Yep, I got you now !!
- Damned ...
Au dernier billet, j'ai décrit l'implémentation, pilotée par les tests, de la méthode Movies#size. La méthode retourne le nombre de films ajoutés via Movies#add.
Néanmoins, Movies utilise un compteur et ne passe pas par une Collection interne pour stocker les instances de Movie. Les tests nous ont permis de développer la solution la plus simple possible.
1. Test: Movies#includes: aMovie
Ajoutons un autre test pour notre collection: Movies#includes: aMovie pour une instance de Movie précédemment ajoutée retourne vrai, sinon faux.
testIncludesAnAddedMovieReturnsTrue | movies starWars bladeRunner alien | movies := Movies new. starWars := Movie newWithTitle: 'Star Wars'. bladeRunner := Movie newWithTitle: 'Blade Runner'. alien := Movie newWithTitle: 'Alien'. movies add: starWars; add: bladeRunner. self assert: (movies includes: starWars). self assert: (movies includes: bladeRunner). self deny: (movies includes: alien).
Notez l'appel self deny : si la méthode TestCase#assert vérifie que l'expression en paramètre retourne true, TestCase#deny passe si l'expression testée retourne false.
Lancez le test. Le debugger s'arrête car Movies#includes:aMovie n'existe pas.
Comme vu au billet précédent, utilisez le bouton Create Method pour la déclarer.
Cette fois-ci, on doit vraiment passer par une collection interne.
includes: aMovie ^ moviesCollection includes: aMovie
Déclarons moviesCollection comme variable d'instance pour la rendre accessible aux autres méthodes de la classe Movies.
Comme toute variable d'instance, elle doit être initialisée. Au hasard, utilisons une instance d'OrderedCollection. Editez Movies#initialize:
initialize super initialize. size:=0. moviesCollection:=OrderedCollection new
En relançant le test, le debugger indique que la première assertion ne passe pas. En utilisant la fonctions watch it sur (movies includes: starWars), le retour est en effet false.
Utilisons un autre outil de debuggage. Sélectionner movies, puis clic-droit, inspect it.
La fenêtre qui apparaît permet de visualiser l'état de l'instance Movies. En cliquant sur size, on voit que la méthode retourne 2. Cela semble logique, nous avons ajouté les instances "Star Wars" et "Blade Runner".
Regardons moviesCollection. Nous avons bien une instance d'OrderedCollection, mais vide (rien entre les parenthèses).
Pour s'en assurer, utilisons l'éditeur de la fenêtre pour demander la taille de moviesCollection. Tapez
moviesCollection size
puis utilisez la fonction inspect it.
On voit que size retourne bien 0 (une instance de la classe SmallInteger).
Les instances de Movie ne sont donc pas ajoutées à moviesCollection. Examinons la méthode Movies#add:
Les instances de Movie ne sont donc pas ajoutées à moviesCollection. Examinons la méthode Movies#add:
add: aMovie size := size + 1
add: aMovie size := size + 1. moviesCollection add: aMovie
et maintenant le test passe !
2. Refactoring.
2.1 movies, starWars, bladeRunner et alien
Supprimons les duplications. Avant toute chose, vérifions que tous les tests de notre package Movies passent.
Les duplications se trouvent dans MoviesSizeTest. Les instances de Movie pour "Star Wars", "Blade Runner" et "Alien" sont créées dans les méthodes testWithOneMovieSizeReturnsOne, testWithThreeMoviesSizeReturnsThree et testIncludesAnAddedMovieReturnsTrue. De plus, chacune des méthode de test instancie Movies.
TestCase propose les méthodes setUp et tearDown pour ce genre de situation. TestCase#setUp est exécutée avant chaque test, et tearDown aprés chaque test. Lorsqu'on exécute tous les tests de MoviesSizeTest, l'appel des méthodes est le suivant (à l'ordre des tests près):
- setUp
- testIncludesAnAddedMovieReturnsTrue
- tearDown
- setUp
- testNewInstanceSizeReturnsZero
- tearDown
- setUp
- testWithOneMovieSizeReturnsOne
- tearDown
- setUp
- testWithThreeMoviesSizeReturnsThree
- tearDown
Nous allons mettre en commun la création des instances de Movie dans la méthode setUp. Définissez MoviesSizeTest#setUp comme suit:
setUp movies := Movies new. starWars := Movie newWithTitle: 'Star Wars'. bladeRunner := Movie newWithTitle: 'Blade Runner'. alien := Movie newWithTitle: 'Alien'.<br />
Les quatre variables sont des variables d'instances. Adaptez ensuite chaque méthode de MoviesSizeTest en vérifiant que les tests passent à chaque fois.
testNewInstanceSizeReturnsZero self assert: movies size = 0
testWithOneMovieSizeReturnsOne movies add: starWars self assert: movies size = 1
testWithThreeMoviesSizeReturnsThree movies add: starWars; add: bladeRunner; add: starWars. self assert: movies size = 3
testIncludesAnAddedMovieReturnsTrue movies add: starWars; add: bladeRunner. self assert: (movies includes: starWars). self assert: (movies includes: bladeRunner). self deny: (movies includes: alien).
2.2 Renommer MoviesSizeTest
Le nom de la classe ne reflète plus assez la totalité des tests, car on vérifie les retours des méthodes Movies#size et Movies#includes. Le vrai objectif est de s'assurer que Movies#add ajoute bien les instances de Movie. Renommons la classe en MoviesAddMovieTest.
Pour ce faire, clic-droit sur la classe et sélectionnez rename.
Saisissez MoviesAddMovieTest comme nom de classe et validez.
Saisissez MoviesAddMovieTest comme nom de classe et validez.
2.3 Supprimer le comteur size de Movies
Regardons Movies#add de nouveau:
add: aMovie size := size + 1. moviesCollection add: aMovie
moviesCollection est une instance d'OrderedCollection.
OrderedCollection#size retourne le nombre d'instance stockées. On peut donc supprimer le compteur size qui fait doublon.
add: aMovie moviesCollection add: aMovie
Relancez les tests:
L'erreur saute aux yeux en ouvrant Movies#size:
size ^ size
Corrigeons la méthode:
size ^ moviesCollection size
et les tests repassent !
Nettoyons au passage Movies#initialize pour supprimer l'initialisation de size:
initialize super initialize. moviesCollection:=OrderedCollection new
et nous pouvons finalement supprimer size des variables d'instances de Movies:
Object subclass: #Movies instanceVariableNames: 'moviesCollection' classVariableNames: '' poolDictionaries: '' category: 'Movies'
3. Pause publicité
Notre collection est minimale mais testée. Comme pour les billets précédents, nous écrivons d'abord le test puis nous nous laissons guider par les erreurs et le debugger pour implémenter le code fonctionnel.
Après chaque test, on modifie le code testé et de test pour l'améliorer.
La prochaine fois, nous retravaillerons MoviesAddMovieTest mais en utilisant les Traits, un mécanisme de réutilisation de code entre classes.
No comments:
Post a Comment