소스 검색

Intro et exemple TDD

Benoît Hubert 7 년 전
부모
커밋
6fd648d68c

+ 3 - 2
react-tuto/src/markdown/4. Bases de Python/01. Premier programme.md

@@ -5,11 +5,12 @@ Pour cela, dégaîne tes armes l'éditeur de texte, et le terminal.
 Dans ton dossier `python-tdd/bases`, crée le fichier `01-premier.py`, avec le contenu suivant :
 
 ```python
+# Cette ligne est un COMMENTAIRE
 message = "Hello galaxy"
 print(message)
 ```
 
-Puis dans le terminal (marche sous OS X, Linux *et* Windows/PowerShell) :
+Puis dans le terminal (Utiliser **python3** sous OS X et Linux, **python**  sous Windows/PowerShell) :
 
     cd ~/CHEMIN/VERS/python-tdd/bases
     python 01-premier.py
@@ -18,6 +19,6 @@ Cela produit l'affichage de `Hello galaxy` dans le terminal. Ce petit programme
 
 > Python est un langage de script, et n'a pas besoin de passer par une phase de compilation.
 
-> Contrairement à JavaScript (souviens-toi du <code><strong>var</strong> variable</code> en JS), on **ne déclare pas** les variables en Python, on les affecte directement.
+> Contrairement à JavaScript (souviens-toi du <code><strong>var</strong> nomVariable</code> en JS), on **ne déclare pas** les variables en Python, on les affecte directement.
 
 > Il n'est pas nécessaire de mettre des points-virgule à la fin des lignes. Ils sont acceptés, mais en pratique, *personne* dans la communauté Python ne les utilise. Leur seule utilité éventuelle est de séparer des instructions sur une même ligne.

+ 7 - 5
react-tuto/src/markdown/4. Bases de Python/02. Fonctions.md

@@ -2,7 +2,7 @@ Voici maintenant un exemple de fonction en Python (crée le fichier `02-fonction
 
 ```python
 # Salue quelqu'un en utilisant son titre
-def greet(name, gender=''):
+def greet_person(name, gender=''):
     if gender == 'male':
         title = 'Mr'
     elif gender == 'female':
@@ -11,8 +11,8 @@ def greet(name, gender=''):
         title = 'Mx'   # titre "neutre"
     print("Hello %s %s" % (title, name))
 
-greet("Johnson", "male")
-greet("May", "female")
+greet_person("Johnson", "male")
+greet_person("May", "female")
 ```
 
 Pour saluer (*greet*) une personne, on utilise le "titre honorifique" suivi du nom. Le titre est déterminé à partir du genre.
@@ -29,6 +29,8 @@ Cette dernière particularité de Python est absolument fondamentale ! Python se
 
 > Essaie de voir ce qui se passe en "désindentant" la ligne `title = 'Mr'` pour la ramener au niveau du `if` qui la précède. **Tu risques de rencontrer cette erreur à nouveau si tu n'es pas rigoureux sur l'indentation**.
 
-Un avantage d'abandonner les `{}` est que le code est moins "chargé" visuellement. Il n'y a pas d'*obligation* quant au nombre d'espaces d'indentation, mais une *convention* très répandue, qu'en pratique tout le monde adopte, préconise l'usage de 4 espaces entre chaque niveau d'indentation (vrais espaces et non tabulation).
+Un avantage d'abandonner les `{}` est que le code est moins "chargé" visuellement. Il n'y a pas d'*obligation* quant au nombre d'espaces d'indentation, ni par rapport à d'autres aspects comme le nommage des variables et des fonctions. Ceci dit, la communauté Python utilise des *conventions* très largement adoptées, qui évitent que chacun(e) adopte sa propre convention. Par exemple :
+* on préconise l'usage de 4 espaces entre chaque niveau d'indentation (vrais espaces et non tabulation).
+* les fonctions et variables utilisent la convention [Snake case](https://fr.wikipedia.org/wiki/Snake_case) c'est à dire des `mots_minuscules_separes_par_underscore`.
 
-Dernière chose, les arguments de `print()` : La partie entre guillemets ressemble à ce qu'on pourrait trouver en C ou en Java : `%s` et `%d` sont des "emplacements" pour des variables (chaîne et entier respectivement). Par contre, la syntaxe de la suite diffère : les valeurs à insérer dans les emplacements sont situées entre parenthèses, suite au caractère `%`.
+Dernière chose, les arguments de `print()` : La partie entre guillemets ressemble à ce qu'on pourrait trouver en C ou en Java : `%s` et `%d` sont des "emplacements" pour des variables (chaîne et entier respectivement). Par contre, la syntaxe de la suite diffère : les valeurs à insérer dans les emplacements sont situées entre parenthèses, suite au caractère `%`.

+ 0 - 11
react-tuto/src/markdown/4. Bases de Python/05. Conclusion provisoire.md

@@ -1,11 +0,0 @@
-On passe à la suite !
-
-Je t'entends demander : &laquo;&nbsp;Quoi, déjà fini ? &Ccedil;a y est, je suis un Maître Jedi du Python ?&nbsp;&raquo;
-
-Heu, ne t'emballe pas, jeune padawan ! Disons que tu en sais assez pour passer à la suite !
-
-Un petit rappel tout de même, s'il ne fallait retenir qu'une chose :
-
-> **Attention** à l'indentation : une erreur d'indentation peut empêcher le programme de se lancer !
-
-Prochaine étape : un mini-serveur web en Python !

+ 19 - 0
react-tuto/src/markdown/4. Bases de Python/05. Intro au TDD.md

@@ -0,0 +1,19 @@
+On a suffisamment de bases pour entrer dans le vif du sujet, et aborder le TDD, ou Test-Driven Development, ou en français Développement piloté par les tests.
+
+> C'est la seule page de théorie pure... Si ça te semble encore un peu trop, n'hésite pas à passer à la section suivante pour un **exemple**.
+
+Le TDD s'intègre dans les "méthodes agiles". Il aide à répondre à la question : **comment développer une application à la fois fiable et maintenable ?**
+
+<img src="https://media.giphy.com/media/g8XkcuerwzVS0/giphy.gif" alt="collapse" style="float: left; padding: 0 15px 15px 0;" />
+
+C'est une question sensible quand le développement s'étale sur des années ! Bien des **projets** informatiques se sont **terminés en désastres** techniques et financiers, faute de pouvoir **maintenir et faire évoluer** le code.
+
+En quoi ça consiste ? Eh bien, c'est en quelque sorte une inversion du cycle "traditionnel" de développement dans les (grosses) entreprises. Avant, on passait du temps à écrire une "spec" parfois massive, détaillant tout ce que devait faire un logiciel. Mais cet effort de réflexion ne permettait pas toujours de prévoir certains "pépins" rencontrés dans la pratique.
+
+Le TDD a une portée résolument *pratique* et utilise quelques concepts simples :
+- Avant d'écrire du code pour *faire* quelque chose, on écrit *d'abord* un test qui va **vérifier que le code qu'on écrit va se comporter comme on l'a prévu**.
+- Au lieu de planifier énormément de choses en amont, on cherche d'abord à créer un **produit minimal** utilisable par des utilisateurs. A partir de cette base, on ajoute des fonctionnalités de façon *incrémentale*, par petites touches.
+
+Le fait d'**écrire les tests en premier** a une conséquence logique : quand on lance les tests juste après les avoir écrits, ils échouent ! Et c'est voulu ! Une fois qu'on a un test qui échoue, on écrit le code qui permet de faire passer le test.
+
+D'une certaine façon, les tests servent à la fois de spécification et de documentation du code. Ecrire des tests peut nous aider à clarifier notre intention avant de se lancer tête baissée dans le code.

+ 104 - 0
react-tuto/src/markdown/4. Bases de Python/06. TDD - exemple 1.md

@@ -0,0 +1,104 @@
+Un exemple : on veut écrire une fonction, qui nous renvoie une valeur booléenne indiquant si on est majeur quand on a l'âge passé en paramètre.
+
+#### Le test
+
+D'abord le test :
+
+```python
+import unittest
+
+class TestIsMajor(unittest.TestCase):
+
+    def test_is_major(self):
+        self.assertTrue(is_major(30))
+        self.assertFalse(is_major(11))
+
+if __name__ == '__main__':
+    unittest.main()
+```
+
+La classe `TestIsMajor` hérite de `TestCase` et de ses méthodes. Parmi celles-ci, des *assertions*, qui permettent de s'assurer qu'on obtient bien le résultat voulu.
+Les deux utilisées ici, `assertTrue()` et `assertFalse()`, veulent s'assurer que l'expression qu'elles reçoivent en paramètre est respectivement vrai ou faux.
+
+Les assertions sont souvent groupées à plusieurs dans une méthode, mais on aurait pu aussi bien remplacer `test_is_major()` par deux méthodes distinctes :
+
+```python
+    def test_is_major(self):
+        self.assertTrue(is_major(30))
+
+    def test_is_not_major(self):
+        self.assertFalse(is_major(11))
+
+```
+
+#### Première exécution : échec attendu
+
+Si on l'exécute tel quel (`python 06-tdd-exemple1.py`), on obtient logiquement une erreur car la fonction `is_major()` n'existe pas :
+```text
+E
+======================================================================
+ERROR: test_is_major (__main__.TestIsMajor)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "06-tdd1-test.py", line 10, in test_is_major
+    self.assertTrue(is_major(30))
+NameError: name 'is_major' is not defined
+
+----------------------------------------------------------------------
+Ran 1 test in 0.000s
+
+FAILED (errors=1)
+```
+A noter : le `E` isolé en première ligne nous indique que l'unique test a fini en *erreur* (ce qui est confirmé par la dernière ligne avec `errors=1`).
+
+#### Petite amélioration...
+
+Tentons une première amélioration, et ajoutons ces deux lignes juste au-dessous de la classe, dans le même fichier (normalement on a les **tests et le code à tester dans des fichiers séparés**) :
+
+```python
+def is_major(age):
+    pass
+```
+
+Voyons ce qui se passe :
+```text
+F
+======================================================================
+FAIL: test_is_major (__main__.TestIsMajor)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "06-tdd1-test.py", line 10, in test_is_major
+    self.assertTrue(is_major(30))
+AssertionError: None is not true
+
+----------------------------------------------------------------------
+Ran 1 test in 0.000s
+
+FAILED (failures=1)
+```
+
+Cela ne semble pas beaucoup mieux, et pourtant, on progresse... Au moins, le test a pu appeler la fonction `is_major()`.
+
+Au lieu d'un `E` isolé en première ligne, on a un `F` pour *failure*. On nous indique en bas `failures=1`.
+
+On a une `AssertionError` car la première assertion a échoué. La deuxième aussi aurait échoué, mais une méthode dans une classe de test est interrompue à la première assertion qui échoue.
+
+#### Résolution :
+
+Voici le code qui fera passer le test :
+```python
+def is_major(age):
+    return True if age >= 18 else False
+```
+
+Résultat :
+```text
+.
+----------------------------------------------------------------------
+Ran 1 test in 0.000s
+
+OK
+```
+
+&Ccedil;a a marché, et le succès est matérialisé par le `.` isolé sur la première ligne (il n'y avait qu'un test).
+Cette convention (`.` pour succès, `F` pour échec, `E` pour erreur) donne un affichage compact, utile quand on a *beaucoup* de tests à faire passer.

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
react-tuto/src/resources/markdown.json