Capítulo 16. Programación Funcional

16.1. Inmersión

En Capítulo 13, Pruebas unitarias (Unit Testing) aprendimos la filosofía de las pruebas unitarias. En Capítulo 14, Programación Test-First implementamos paso a paso una prueba unitaria en Python. En Capítulo 15, Refactorización vimos cómo las pruebas unitarias hacen más sencilla la refactorización a gran escala. Este capítulo se apoyará en esos programas de ejemplo, pero aquí nos centraremos en técnicas más avanzadas específicas de Python, en lugar de en las pruebas unitarias en sí.

Lo que sigue es un programa de Python completo que funciona como infraestructura de pruebas de regresión rudimientaria. Toma las pruebas unitarias que hemos escrito para módulos individuales, los junta todos en una gran batería de pruebas y los ejecuta todos a la vez. Yo mismo uso este script como parte del proceso de compilación de este libro; tengo pruebas unitarias para muchos de los programas de ejemplo (no sólo el módulo roman.py que aparece en Capítulo 13, Pruebas unitarias (Unit Testing)), y la primera cosa que hace mi script de compilación automático es ejecutar este programa para asegurarse de que todos mis ejemplos siguen funcionando. Si esta prueba de regresión fallase, la compilación se detiene automáticamente. No quiero publicar ejemplos que no funcionen más de lo que usted querría bajarlos y sentarse rascándose la cabeza y gritándole al monitor mientras se pregunta por qué no funcionan.

Ejemplo 16.1. regression.py

Si aún no lo ha hecho, puede descargar éste ejemplo y otros usados en este libro.

"""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")

Ejecutar este script en el mismo directorio del resto de los script de ejemplo del libro hará que encuentre todas las pruebas unitarias, llamadas módulotest.py, las ejecutará como una sola prueba y todas pasarán o fallarán a la vez.

Ejemplo 16.2. Salida de ejemplo de regression.py

[usted@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 Las 5 primeras pruebas son de apihelpertest.py, que comprueba el script de ejemplo de Capítulo 4, El poder de la introspección.
2 Las 5 pruebas siguientes son de odbchelpertest.py, que comprueba el script de ejemplo de Capítulo 2, Su primer programa en Python.
3 El resto son de romantest.py, que estudiamos en profundidad en Capítulo 13, Pruebas unitarias (Unit Testing).