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 --coverage donne programme.gcno
  • on lance le programme ./programme, on obtient programme.gcda
  • on lance gcov programme avec option -b -c, on obtient programme.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