-
Cours :
- Codage des nombres
- cours 1
transparents : pdf, html - planche de TD/TP 1 (pdf)
- cours 1
- Texte, fichiers et images
- cours 2
transparents : pdf, html - planche de TD/TP 2 (pdf)
- cours 2
- Tests
- cours 3
transparents : pdf, html - planche de TD/TP 3 (pdf)
- cours 3
- HTML/CSS
- cours 4
transparents : pdf, html - planche de TD/TP 4 (pdf)
- cours 4
- Javascript 1.0
- cours 5
transparents : pdf, html - planche de TD/TP 5 (pdf)
- cours 5
- Javascript 2.0
- Diviser pour régner
- cours 7
transparents : pdf, html - planche de TD/TP 7 (pdf)
- cours 7
- Didactique
- cours 8
transparents : pdf, html - planche de TD/TP 8 (pdf)
- cours 8
Tests
Tutoriel utilisant Pycharm
premiers tests
Créez un nouveau projet avec PyCharm que l’on pourra appeler essai_tests
, puis ajoutez-y un fichier que vous nommerez mathematiques.py
. Ce fichier contiendra le code suivant :
Un test sans bibliothèque
Pour tester ce code, j’imagine que si les deux conditions suivantes sont remplies : * double(0)
vaut 0
, * double (21)
vaut 42
ma méthode sera exacte. On utilise le mot clé assert pour créer notre fonction de test.
Attention : Les fonctions de tests doivent toutes commencer par
test_
.
Ajoutez la méthode ci-après à votre fichier :
et exécutez-la en fin de programme : test_double()
Si tout s’est passé comme prévu, il ne s’est rien passé. Normal, l’ assert
était vérifié. Changez un des assert
de la fonction test_double
pour que le résultat soit faux (par exemple assert double(0) == 7
). Le programme doit maintenant s’arrêter sur une exception. Chez moi, j’obtiens ça :
Traceback (most recent call last):
File "/Users/francois/Documents/pycharm/essai_tests/mathematiques.py", line 10, in <module>
test_double()
File "/Users/francois/Documents/pycharm/essai_tests/mathematiques.py", line 6, in test_double
assert double(0) == 7
AssertionError
Ainsi, si tout se passe bien, nos tests sont passés, si le programme s’arrête sur une exception de type AssertionError
, nos tests ne correspondent pas à la réalité. Nous sommes en face d’un bug (qu’il faut corriger).
Utilisation de l’environnement de test avec Pycharm
Nous allons demander à l’environnement py.test d’exécuter nos tests. Si ce n’est pas encore fait, Il faut installer le module pytest
(pip3 install pytest
ou via pycharm).
Il nous donnera plus d’informations sur les tests réussis ou échoués (une application normale contient des centaines de tests). Puis nous allons demander à Pycharm d’exécuter mathematiques.py
à l’aide de notre environnement de test.
Pour cela, créez un environnement d’exécution et créez une configuration pyhton test > py.test
. Ici, les paramètres dont nous aurons besoin sont :
- le champ
name
, qui donne un nom à notre contexte. Par exemple “mes tests” - le champ
target
, qui spécifie quel script utiliser. Cliquez tout à droite de ce champ sur un petit bouton avec…
puis choisissez le fichiermathematiques.py
Une fois ceci configuré, cliquez sur le bouton OK
.
Un nouvel environnement de tests est créé dans le menu run
. Exécutez-le. Vous devriez voir une nouvelle fenêtre en bas de l’écran PyCharm apparaître et vos tests s’exécuter. Si tout s’est bien passé, une barre verte doit apparaître.
Pour finir cette partie :
- Séparez votre fonction de tests en 2 fonctions (chaque fonction de test ne doit contenir qu’une chose à tester, donc a priori qu’un seul
assert
). - exécutez votre nouvel environnement.
- Ajoutez une fonction de test qui plante. Exécutez votre environnement de test. Voyez la barre rouge. Supprimez ce test non valide.
Séparer code et tests
Placez la fonction de test (et son exécution) dans un fichier que vous nommerez test_mathematiques.py
. Faites en sorte qu’il s’exécute sans problème (attention aux import
).
On séparera toujours les tests du code. Tout fichier de test commence par
test_
.
Dans le module d’exécution de test, vous pouvez maintenant donnez le répertoire de votre projet comme source de tests. Pytest prendra automatiquement tous les fichiers qui commencent par test_
comme fichiers de tests et à l’interieurs de ceux ci les fonctions qui commencent par test_
comme des tests. Ceci vous permet d’exécuter en un click tous les tests de votre projet répartis en plusieurs fichiers de tests.
Les tests en ligne de commande
La bibliothèque http://pytest.org peut directement s’exécuter depuis le terminal. En supposant que votre fichier de test s’appelle test_mathematiques.py
et que vous vous trouviez dans le bon répertoire, la commande : python3 -m pytest test_aide_mathematiques.py
va exécuter vos tests, comme vous le feriez depuis PyCharm.
Utilisation des tests
Analyse d’algorithme
Exemple du tri par sélection
L’algorithme fonctionne ainsi : à l’étape \(i\) l’algorithme place le ième plus petit élément en position \(i-1\) du tableau
Que devrions nous tester ? Cas général des tris :
- tableau simple à un élément : normalmenet les algorithmes ne font rien
- tableau déjà trié de petite taille : les algorithmes travaillent mais ne doivent rien faire
- tableau trié à l’envers : parfois donne les cas limites
- tableau non trié
Question 1. En utilisant le code de l’algorithme ci-dessous, créez les 4 tests proposés. Vérifiez que vos tests sont bien ok en ajoutant un test qui plante, puis en modifiant l’algorithme pour qu’il ne trie plus.
def selection(tab):
for i in range(len(tab) - 1):
min_index = i
for j in range(i + 1, len(tab)):
if tab[j] < tab[min_index]:
min_index = j
tab[i], tab[min_index] = tab[min_index], tab[i]
Quelques règles :
- un tri doit être reproductible. On n’utilise donc pas le hasard dans les tests (le tableau ne doit pas être mélangé par shuffle par exemple). Sinon un bug peut apparaitre de façon aléatoire.
- pas trop de tests. Mais si on est pas sur, autant le rajouter. On pourra toujours l’enlever plus tard. Ici, est ce que tester des tableau avec des égalités à un sens ?
Preuve du programme
Exemple sur le code de césar. Les tests permettent :
- aux élèves de chercher à comprendre un bout de code : on donne le code d’une fonction et on demande aux élèves d’écrire les tests pour comprendre le fonctionnement.
- aux enseignants de vérifier que le code produit par les élèves marche juste en exécutant les tests (code de césar)
Compréhension du code : exemple de la suppression d’accent
Il est parfois utile se supprimer tous les accent d’un texte pour avoir moins de lettres différentes.
On utilise pur cela un truc unicode, la normalisation ‘NFD’. En unicode, les caractères accentués peuvent s’écrire sous deux formes : soit la glyphe é
soit une combinaison de glyphes : la glyphe e
suivie de la glyphe d’accent '
.
Dans un texte en français, la lettre de base est une lettre présente dans le code ascii, mais pas l’accent. En transformant alors un texte français normalisé en NFD en ascii on supprime les caractères qu’il ne connait pas, donc tous les accents.
Exemple de la transformation :
import unicodedata
s = "éçà ü ?"
print(s)
s2 = unicodedata.normalize('NFD', s)
print(s2) # pas de différence, c'est toujours de l'utf-8 par encodé différemment
s3 = s2.encode('ascii', 'ignore')
print(s3) # c'est du bytes maintenant
s_sans_accent = s3.decode('utf-8')
print(s_sans_accent) # de l'utf-8 sans accent
Question 2. Testez le bout de code ci-dessus. Créez une fonction (dans transformations.py
) que vous nommerez sans_accent
qui prend un texte en paramètre et le rend sans accent. Testez la fonction sans_accent
en vérifiant qu’une chaine avec accent est bien transformée en une chaine sans accent. Créez une fonction (dans transformations.py
) que vous nommerez majuscules_sans_accent
qui prend un texte en paramètre et le rend sans accent et en majuscule (méthdoe upper
des listes). Testez la fonction majuscules_sans_accent
.
Production de fonction testés : exemple du code de César
Cette façon de coder des messages très ancienne, César l’aurait utilisée, repose sur une substitution monoalphabétique particulière, c’est à dire remplacer une lettre de l’alphabet par une autre.
Le principe en est simple, chaque lettre de l’alphabet possède une valeur de 1 à 26 (A vaut 1, B vaut 2, …, Z vaut 26), que l’on code en lui rajoutant une constante modulo 26.
On a alors coutume de considérer que la clé permettant de coder le texte est la lettre correspondant au codage de ‘A’. Ainsi, l’ajout de la constante 4 correspond à la clé ‘E’, comme le montre la table suivante :
clé E | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
initiale : | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
codée : | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | A | B | C | D |
Le texte "LE VENDREDI C'EST ALGORITHMIE"
devient alors "PI ZIRHVIHM G'IWX EPKSVMXLQMI"
avec "E"
comme clé (les caractères qui ne sont pas des majuscules sont ignorées dans le codage).
Question 3. Dans cesar.py
, créez une fonction que vous appellerez code_cesar
qui prend une lettre en majuscule en paramètre (le code) et rend un dictionnaire dont les clés sont les lettres en majuscules et la valeur l’encodage de cette lettre selon le code donné en paramètre. Testez votre méthode. Elle doit rendre {'A': 'E', 'B': 'F', 'C': 'G', 'D': 'H', 'E': 'I', 'F': 'J', 'G': 'K', 'H': 'L', 'I': 'M', 'J': 'N', 'K': 'O', 'L': 'P', 'M': 'Q', 'N': 'R', 'O': 'S', 'P': 'T', 'Q': 'U', 'R': 'V', 'S': 'W', 'T': 'X', 'U': 'Y', 'V': 'Z', 'W': 'A', 'X': 'B', 'Y': 'C', 'Z': 'D'}
pour un paramètre valant 'E'
.
Refactoring
Une fois qu’une fonction est crée et testée, il est aisé de la modifier sans la casser. Ceci est particulièrement utile pour séparer un algorithme compliqué en plusieurs parties plus simple.
En cours, cela permet aux élèves d’avoir une compréhension plus fine de l’algorithme – souvent décrit en un seul tenant dans les livre et sur wikipédia – en le découpant en parties fonctionnelles.
Exemple du tri par sélection. Ce tri effectue 2 sous-tâches pour fonctionner : recherche du minimum et échange de deux valeurs.
Nous allons extraire ces deux sous-fonctions. Comme notre méthode de tri est testée, on saura tout de suite si cela rate ou pas.
Question 4. En vérifiant régulièrement, en exécutant vos tests, que tout fonctionne encore:
* Créez une méthode nommée `échange` qui à partir d’un tableau et de deux indices, les échange.
* Testez-la.
* Remplacez l’échange dans le tri par sélection par la nouvelle fonction.
Question 5. De même:
* Créez une méthode nommée `min_indice_tableau` qui à partir d’un tableau et d’un indice, rend l’indice du plus petti élément.
* Testez-la.
* Remplacez l’échange dans le tri par sélection par la nouvelle fonction.
Calcul de puissances
Question 6. Proposez des tests pour l’algorithme du calcul de la puissance :
def puissance(nombre, exposant):
resultat = 1
compteur = exposant
while compteur > 0:
resultat *= nombre
compteur -= 1
return resultat
Question 7. Adaptez le code précédent pour implémenter une exponentiation rapide. Procédez par étapes : chaque étape doit être simple et accompagnée d’un test si nécessaire.
Création par les tests
Partie la plus difficile mais également la plus utile et gratifiante une fois qu’on l’a comprise et qu’on l’utilise. On peut créer un algorithme ou un programme compliqué juste avec des tests. En ajoutant petit à petit de la complexité dans l’algorithme sans le casser (puisque les tests passent). L’exemple que l’on va utiliser est simple, mais cela fonctionne admirablement bine avec des problèmes bien plus compliqué dont, souvent, on a pas la bonne réponse immédiatement.
Question 8. Utilisez la programmation par les tests pour réaliser l’algorithme glouton de rendu de monnaie vu en première semaine.
L’algorithme doit prendre en entrée deux paramètres :
- le système de pièce sous forme d’une liste
- la valeur à rendre
Comme à chaque fois, commencez petit et ajouter des cas simples (et leurs tests) qui complexifieront votre code.