Chapitre 16. Programmation fonctionnelle

16.1. Plonger

Au Chapitre 13, Tests unitaires, vous avez appris la philosophie des tests unitaires. Au Chapitre 14, Ecriture des tests en premier, vous avez suivi pas à pas l'implémentation de tests unitaires en Python. Au Chapitre 15, Refactorisation, vous avez vu comment les tests unitaires facilitent la refactorisation à grand échelle. Ce chapitre va poursuivre le développement de ces programmes, mais cette fois en mettant l'accent sur des techniques avancées de Python plutôt que sur les test unitaires proprement dit.

Voici un programme Python complet qui remplit le rôle de framework pour les tests de régression. Il prend les tests unitaires que vous avez écrits pour chaque modules, les assemble en une seule suite de tests et les exécute en une seule fois. J'utilise ce script pendant la procédure de construction de ce livre, j'ai des tests unitaires pour plusieurs programmes d'exemple (pas seulement le module roman.py du Chapitre 13, Tests unitaires) et la première chose que mon script de construction automatique fait est d'exécuter ce programme pour être sûr que tous mes exemples fonctionnent encore. Si ce test de régression échoue, la construction s'arrête immédiatement. Je n'ai pas plus envie de publier un exemple qui ne marche pas que vous de le télécharger et de vous gratter la tête face à l'écran en vous demandant ce qui ne va pas.

Exemple 16.1. regression.py

Si vous ne l’avez pas déjà fait, vous pouvez télécharger cet exemple ainsi que les autres exemples du livre.

"""Regression testing framework

This module will search for scripts in the same directory named
XYZtest.py.  Each such script should be a test suite that tests a
module through PyUnit.  (As of Python 2.1, PyUnit is included in
the standard library as "unittest".)  This script will aggregate all
found test suites into one big test suite and run them all at once.
"""

import sys, os, re, unittest

def regressionTest():
    path = os.path.abspath(os.path.dirname(sys.argv[0]))   
    files = os.listdir(path)                               
    test = re.compile("test\.py$", re.IGNORECASE)          
    files = filter(test.search, files)                     
    filenameToModuleName = lambda f: os.path.splitext(f)[0]
    moduleNames = map(filenameToModuleName, files)         
    modules = map(__import__, moduleNames)                 
    load = unittest.defaultTestLoader.loadTestsFromModule  
    return unittest.TestSuite(map(load, modules))          

if __name__ == "__main__":                   
    unittest.main(defaultTest="regressionTest")

À l'exécution de ce script dans le même répertoire que le reste des scripts d'exemple de ce livre, l'ensemble des tests unitaires, nommés moduletest.py, sont trouvés, exécutés comme un seul test, réussissant ou échouant ensemble.

Exemple 16.2. Exemple de sortie de regression.py

[you@localhost py]$ python regression.py -v
help should fail with no object ... ok                             1
help should return known result for apihelper ... ok
help should honor collapse argument ... ok
help should honor spacing argument ... ok
buildConnectionString should fail with list input ... ok           2
buildConnectionString should fail with string input ... ok
buildConnectionString should fail with tuple input ... ok
buildConnectionString handles empty dictionary ... ok
buildConnectionString returns known result with known input ... ok
fromRoman should only accept uppercase input ... ok                3
toRoman should always return uppercase ... ok
fromRoman should fail with blank string ... ok
fromRoman should fail with malformed antecedents ... ok
fromRoman should fail with repeated pairs of numerals ... ok
fromRoman should fail with too many repeated numerals ... ok
fromRoman should give known result with known input ... ok
toRoman should give known result with known input ... ok
fromRoman(toRoman(n))==n for all n ... ok
toRoman should fail with non-integer input ... ok
toRoman should fail with negative input ... ok
toRoman should fail with large input ... ok
toRoman should fail with 0 input ... ok
kgp a ref test ... ok
kgp b ref test ... ok
kgp c ref test ... ok
kgp d ref test ... ok
kgp e ref test ... ok
kgp f ref test ... ok
kgp g ref test ... ok

----------------------------------------------------------------------
Ran 29 tests in 2.799s

OK
1 Les 5 premiers tests viennent de apihelpertest.py, qui teste le script d'exemple du Chapitre 4, Le pouvoir de l’introspection.
2 Les 5 tests suivant viennent de odbchelpertest.py, qui teste le script d'exemple du Chapitre 2, Votre premier programme Python.
3 Les tests restant viennent de romantest.py, que vous avez étudié en détail au Chapitre 13, Tests unitaires.