Tests
"Testing shows the presence, not the absence of bugs" (Dijkstra, Software Engineering Techniques)
Motivation
Utilisation
- Pour systèmes critiques : vérification formelle (model checking, assistant de preuve)
- Dans le reste de l'industrie : on fait du test
Croyance sur le test
- ça prend du temps => mais moins que tout débuguer
- c'est pas utile
- on ne sait pas comment s'y prendre
Bugs célèbres qui auraient pu être évités
- Ariane 5 (1996) : débordement sur la valeur des entiers (entiers grands devient entiers négatifs)
- Mars Orbiter (1999) : problème d'unités (pouces vs centimètres genre)
- CrowdStrike (2024) : panne "microsoft"
Vocabulaire
- tester = exécuter le programme pour trouver des erreurs
- erreur = comportemnet du programme différent des attentes
- attentes = spécification
- tests fonctionnels = est-ce que le code fonctionne comme on veut ?
- comme : tests unitaires, tests d'intégration, tests système
- aussi : tests de propriété, de non-régression (i.e. même si le code est modifié, les tests existants passent toujours)
- cf. cycle en V tests non-fonctionnels : test de performance, test d'intrusion (sécurité)
Comment on teste ?
- boite blanche : on a tout le code sous les yeux
- boîte noire : on n'utilise pas le code
Tests unitaires
Basic Testing
On crée des fonctions qui commence par test_.
def inc(x):
return x + 1
def test_inc():
assert inc(3) == 5
Then run pytest.
Tests in comments
You can write tests in the documentation.
def inc(x: int):
""" return the integer that follows x
Args:
x (int): a integer
Returns:
_int_: x+1
>>> inc(2)
3
"""
return x + 1
In order to perform the tests, run:
pytest --doctest-modules
You can also create files test_XAIJZPAUZXIUZABIZABC.txt for instance containing
# content of test_example.txt
hello this is a doctest
>>> x = 3
>>> x
3
See more information here: https://docs.pytest.org/en/stable/how-to/doctest.html
Test de couverture
- couverture des lignes de code (i.e. "noeuds de noeuds visités dans le graphe de flot de contrôle")
- couverture des décisions
- couverture des conditions (tous les cas des conditions)
- couverture de chemins (tous les chemins possibles du graphe de flot de contrôle)
C'est un test en boîte blanche, car on connaît le code.
En python
paquet : coverage
coverage run
coverage run --branch
coverage report
coverage html
Mais c'est un outil qui gère la converture de code comme ça... alors que l'on peut plutôt gérer la couverture avec du test.
Pour cela, pytest --cov=dossieroùilyalessources
Dans un fichier .coveragerc mettre ça pour éviter des erreurs de couverture sur des trucs stupides :
[report]
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover
# Don't complain if tests don't hit defensive assertion code:
raise NotImplementedError
En C
Programmes : gcov, lcov, genhtml
gcc --coveragedonneprogramme.gcno- on lance le programme
./programme, on obtientprogramme.gcda - on lance
gcov programmeavec option-b -c, on obtientprogramme.c.gcov - puis
lcov [--branch-coverage] - puis
genhtml ...
Test guidé par les données
C'est un test en boîte noire. On connait :
- la spécification
- le but du programme
- mais pas le code
On veut un jeu de test :
- qui couvre tous les cas, surtout les cas limites
- de taille minimale
- equivalence partitioning
Exemple pour le calcul de la valeur absolue :
def abs(x):
if x > 0:
return x
else x <= 0:
return -x
x = 1 ou -1 ou 0 c'est ok (0 = cas limite)
Tests automatiques
- Test aléatoire
- Exécution symbolique : model checking Le fuzzing consiste à générer automatiquement beaucoup de cas de tests... créer des entrées par mutation ou à partir d'une grammaire. Le but est de maximiser la couverture, ou cibler un type de vulnérabilités.
Exemple : https://en.wikipedia.org/wiki/American_Fuzzy_Lop_(software)
Typiquement, un algo génétique pour augmenter la couverture de code.
Conclusion
Sûreté : système fonctionne comme prévu Sécurité : système résiste à des personnes malintentionnées
Source
Vidéo de Yaëlle Vinçont (ENS Rennes) au Centre International de Rencontres Mathématiques :
- cycle en V 15:44
- Test automatique à '46