Programación defensiva

Es una técnica que trata de acotar todas las situaciones anómalas. La más habitual es la validación de parámetros:


In [6]:
def sqrt(x):
    assert x > 0, "error: valor negativo"
    pass
    
sqrt(-2)


---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-6-91bbf0c1a20c> in <module>()
      3     pass
      4 
----> 5 sqrt(-2)

<ipython-input-6-91bbf0c1a20c> in sqrt(x)
      1 def sqrt(x):
----> 2     assert x > 0, "error: valor negativo"
      3     pass
      4 
      5 sqrt(-2)

AssertionError: error: valor negativo

Pero se puede utilizar para muchas otras cosas:

  • Comprobación de tipos
  • Precondiciones y postcondiciones
  • Control de invariantes y sanity checks

Pruebas automáticas

La función assert() permite hacer pruebas automáticas rudimentarias:


In [5]:
assert(abs(3) == 3)
assert(abs(-9) == 9)

Cuando escribamos una función o método debemos probar los casos típicos y los valores límite para comprobar que se comporta según lo esperado. En próximas sesiones veremos cómo crear auténticos tests unitarios y cómo ejecutarlos con facilidad.

Para hacer comprobaciones en funciones que devuelven flotantes, debemos comprobar la diferencia con el error admitido.


In [11]:
import math
assert(abs(math.sin(1) - 0.84) <= 0.01)

Para comprobar que una instrucción eleva una excepción se puede generar un error de aserción de no producirse:


In [10]:
try:
    math.sqrt(-2)
    raise AssertException("Exception ValueError not raised")
except ValueError:
    pass

Este tipo de pruebas puede ser suficiente para pruebas muy sencillas, pero para pruebas unitarias completas y bien organizadas se aconseja utilizar el módulo unittest.