Bueno, pues sólo por haberlo intentado, ya me he encontrado con ciertas dificultades, que me han servido para reflexionar un poco y llegar a algunas conclusiones.
Diseña para probar
La primera es que el sistema tiene que estar diseñado para ser probado. Es muy difícil probar un sistema que no está pensando con el proceso de pruebas en mente. Los criterios de acoplamiento y cohesión son en mi opinión de especial importancia, y tener este proceso presente favorece su aplicación. En particular, disponer de clases poco acopladas facilita el diseño de los casos de prueba al no ser necesario simular demasiadas de esas clases. Para ilustrar esta reflexión y las siguientes, voy a describir el caso particular que me llevó a ellas.
El sistema es una aplicación web con arquitectura en tres capas (presentación, lógica y datos) con sus funciones habituales. Ciertas operaciones usadas habitualmente por varias clases de la capa de presentación fueron recogidas en varios métodos de clase. Una de estas funciones determina si la IP del navegador pertenece a la red local o no. Su signatura tal y como estaba programada en un principio es la siguiente (Visual Basic.NET):
Public Shared Function EsIPInterna() As BooleanEl principal problema era que ¡no recibía ninguna dirección IP! Examinándo el código, comprobe que la dirección IP se obtenía de la cabecera HTTP enviada por el navegador:
:
:La función dependía internamente de un objeto disponible en el contexto del Internet Information Server de Microsoft. Las pruebas deben ejecutarse en un entorno que desde luego no es el IIS y en el que por tanto no tenemos acceso al objeto Request. Para salvar este primer inconveniente, modifiqué la signatura de la función de esta forma:
Dim direccionIp As String = Request.ServerVariables("HOST_ADDRESS") 'O algo así
:
Public Shared Function EsIPInterna(ByVal ip As String) As BooleanY a continuación, cree una nueva función que permitiría no modificar el resto del código:
:
Public Shared Function EsIPInterna() As BooleanLa primera función me permitiría pasar varios argumentos a la función y poder probarla. Lo dicho, las pruebas tienen que estar siempre presentes en el proceso de diseño y construcción.
Return EsIPInterna(Request.ServerVariables("..."))
End Function
Prueba la reusabilidad
Como segunda reflexión, he percibido que el proceso de pruebas puede favorecer la reusabilidad. En efecto, el obligar a probar una u otra función con un juego de datos que cubra por ejemplo el criterio de pruebas de caja negra obliga a exponer aquellos parámetros que sean necesarios para ejercitar el código. Esta exposición En otro caso, el sistema debe cambiar para adecuar las pruebas. Mejor hacerlo entonces desde el principio. Lo hemos visto en el caso anterior. La función EsIPInterna que recibe el parámetro podría ser reusada en otros proyectos.
Prueba a desacoplar
Probar un sistema casi obliga a disminuir todo lo posible el acoplamiento. La necesidad de probar las clases por separado fuerza en cierta forma a diseñarlas de manera que dependan lo menos posible unas de otras. Para que el proceso de pruebas sea efectivo, es necesario en todo caso que dicha dependencia sea explícita (por ejemplo, en la forma de parámetros en la construcción). Además, se refuerza la esencia colaborativa del diseño orientado a objetos.
Castillos en el aire
Las pruebas son especialmente difíciles de diseñar en aquellos casos en los que el código depende de alguna plataforma tecnológica, precisamente porque es difícil simular dicha plataforma (salvo que, una vez más, el sistema esté diseñado de forma que lo permita). Ejemplos de dichas plataformas son el servidor web (un IIS en mi caso), o un middleware o monitor transaccional (COM+ en mi caso). En el ejemplo esta reflexión se hace evidente.
Conclusiones
Como resumen, probar te permite orientar tu diseño para permitirte precísamente poder probarlo, aumentar su reusabilidad, disminuir su acoplamiento y abstraer lo más posible tu código de la plataforma tecnológica que estés usando en cada momento. No se le puede pedir más a una función... Veremos a ver qué aprendo de las próximas cientos de miles...