Pruebas automatizadas: comprobar una regla sin abrir un modelo
Abrir Revit para averiguar si un código está en un catálogo es una ceremonia bastante cara. Hay que arrancar la aplicación, localizar el proyecto, preparar un elemento y recordar qué resultado debía producir. Si la decisión solo necesita dos valores que ya podemos representar en memoria, toda esa preparación añade dependencias a una pregunta pequeña. Admito que una ventana de progreso aporta solemnidad. No aporta una expectativa verificable.
Vamos a probar una regla de clasificación con Python y C#, sin un modelo ni credenciales. Utilizaremos el contrato del artículo sobre funciones: un código y un catálogo producen un estado. Esta vez escribiremos también qué respuestas esperamos y comprobaremos que una modificación incorrecta puede hacer fallar la prueba. Ese detalle separa una comprobación de una pantalla verde que se limita a confirmar lo que acabamos de copiar del programa.
La expectativa debe venir de la regla, no de su implementación
Nuestro contrato distingue código nulo, texto vacío y texto no perteneciente al catálogo. Nulo devuelve no evaluable; vacío o compuesto solo por espacios devuelve incumple; un texto original presente en el catálogo devuelve cumple. Conservamos mayúsculas y espacios exteriores significativos: " D01 " no se transforma silenciosamente en "D01". Un valor que no sea texto ni nulo queda fuera de la entrada admitida y produce un error de tipo explícito.
Esa última comprobación hace visible una condición que el primer ejemplo de funciones dejaba a cargo del llamador. No estamos ampliando lo que significa un código válido; estamos definiendo cómo esta versión responde cuando alguien incumple su contrato de entrada. La prueba debe recoger esa decisión, en lugar de aceptar cualquier excepción accidental que aparezca dentro de la función.
Guarda el siguiente archivo como reglas_puertas.py. La condición if __name__ == "__main__": ejecuta una demostración solo cuando abres el archivo directamente: imprimirá cumple. Al importarlo desde las pruebas, esa llamada no se ejecuta. Así puedes comprobar la regla sin activar lectura de archivos, ventanas o escrituras en otro sistema.
El resultado esperado debe definirse antes de ejecutar cada caso. D01 con un catálogo que contiene D01 debe cumplir por pertenencia, no porque ese código nos parezca particularmente simpático. D01 con un catálogo que solo contiene D02 debe incumplir. Esta segunda expectativa descubre una implementación que haya escrito D01 como excepción fija en lugar de consultar la entrada recibida.
Una prueba que calcule el resultado esperado copiando las mismas condiciones de la función puede repetir su error. Tampoco sirve llamar dos veces al programa y comparar ambas respuestas para demostrar que son correctas: un fallo determinista puede ser muy constante. La expectativa expresa una decisión del contrato con un dato concreto; la ejecución nos dice si la implementación la respeta.
Una prueba pequeña prepara datos, ejecuta y compara
Python incluye unittest, que permite agrupar comprobaciones y obtener un resultado de ejecución. Guarda el siguiente archivo como test_reglas_puertas.py en la misma carpeta que la función. La clase agrupa los métodos de prueba; self es la referencia que utiliza ese marco para ofrecer métodos como assertEqual y assertRaises. No necesitas diseñar una jerarquía de objetos del edificio para usar esta estructura mínima.
Cada método prepara una entrada, ejecuta la función y compara con una expectativa explícita. assertRaises comprueba el error acordado para un tipo incorrecto; no certifica que cualquier excepción sea aceptable. Los subcasos permiten revisar varios valores de la misma regla y conservar cuál falló. Los siete métodos cubren decisiones diferentes sin necesitar siete proyectos ni siete puertas reales.
La referencia de unittest explica el marco. Para ejecutar nuestros archivos desde esa carpeta, utiliza este comando en una instalación de Python 3.12:
Con los archivos anteriores, el ejecutor informa de siete pruebas y termina con OK. Si aparece un error de importación, comprueba que los dos archivos están juntos y que el comando se ejecuta desde esa carpeta. Si falla una expectativa, lee el nombre y los valores de la comparación antes de modificar nada. El informe no es un juicio sobre la capacidad del autor; es información sobre una diferencia que merece atención. Algunos programas agradecerían que sus desarrolladores se lo tomasen con la misma serenidad.
Comprueba que la prueba sabe detectar una modificación incorrecta
Una prueba que nunca hemos visto fallar todavía puede contener una expectativa equivocada, no estar ejecutándose o no alcanzar la decisión que nos interesa. Para comprobarlo en este ejercicio, guarda los archivos y cambia temporalmente la consulta al catálogo por una condición que admita siempre D01. No conserves esa modificación: su única finalidad es comprobar que el caso del catálogo alternativo detecta la desviación.
Al ejecutar de nuevo, debe fallar test_utiliza_y_conserva_el_catalogo. La función defectuosa devuelve cumple para D01 aunque el catálogo solo contenga D02. Después restaura la consulta de pertenencia y vuelve a ejecutar; las siete pruebas deben regresar a OK. El fallo aporta evidencia de que hemos comprobado ese comportamiento concreto, sin convertir la muestra en una garantía universal.
El mismo criterio ayuda a elegir nuevos casos. Si una modificación que nos preocupa seguiría pasando todas las pruebas, falta una expectativa que la distinga o el contrato necesita una decisión más precisa. Añadir veinte llamadas con códigos admitidos no suele descubrir un problema en la rama del nulo. El número de pruebas es una cifra fácil de enseñar; su capacidad para separar decisiones correctas e incorrectas exige leerlas.
No hace falta convertir cada línea en una prueba que imite su estructura. Por ejemplo, comprobar que el código fuente contiene la palabra return no demuestra que la clasificación sea correcta. Preferiría conservar casos sobre pertenencia, vacío, tipos y efectos sobre el catálogo. Esas propiedades seguirán importando aunque mañana reorganices las condiciones sin cambiar el contrato.
C# puede comprobar el mismo contrato sin conectar servicios
El siguiente programa de consola para .NET 8 incluye un comprobador mínimo. Cada diferencia lanza una excepción y detiene la ejecución con fallo; el mensaje final solo aparece si se han satisfecho las expectativas anteriores. Es útil para entender la mecánica sin instalar paquetes. No ofrece descubrimiento de pruebas ni los informes de un marco de pruebas de .NET.
La firma restringe el código a string?; una llamada con un entero no compila. Por eso no copiamos literalmente la prueba de tipo dinámico de Python. El contrato se protege en lugares distintos según el lenguaje. En ambos casos seguimos necesitando comprobar el significado del texto y el catálogo recibido: el compilador no sabe por qué D01 debería cumplir en un proyecto concreto.
Si sustituyes temporalmente catalogo.Contains(codigo) por una comparación fija con D01, este comprobador debe fallar en el catálogo alternativo. Restaura después la versión correcta. Cuando la colección de pruebas crezca, un marco permitirá aislar casos y continuar informando de varios fallos; esta consola demuestra la comparación y su resultado, sin fingir que ya hemos configurado una infraestructura completa.
Las prácticas de pruebas unitarias de .NET sirven para profundizar en la organización y legibilidad. Para una regla pequeña, la decisión principal es mantener las expectativas claras y las dependencias acotadas. Un proyecto de pruebas magníficamente organizado que solo comprueba el camino feliz sigue dejando el resto del contrato a cargo del optimismo.
Lo probado termina donde empiezan las dependencias que no hemos ejecutado
Estas comprobaciones acreditan la clasificación sobre datos en memoria. No demuestran que un parámetro real se haya leído correctamente, que sus unidades se hayan convertido bien ni que el usuario tenga permiso para aplicar una modificación. Esas fronteras necesitan pruebas de integración y casos representativos en el entorno correspondiente. Separar la regla permite probar una parte con rapidez y reconocer qué parte sigue requiriendo la aplicación.
Una arquitectura que obliga a abrir un modelo para probar todas las condiciones mezcla responsabilidades que podrían revisarse por separado. Eso no significa sustituir siempre los servicios reales por objetos ficticios: una simulación puede repetir nuestras suposiciones y pasar por alto cómo responde la API. Utiliza la prueba pequeña para la decisión pequeña y conserva la comprobación real para el contrato con el sistema externo.
Antes de añadir otro caso a esta colección, explica qué diferencia nueva detectaría. Un catálogo vacío debe hacer incumplir cualquier código no vacío; una entrada nula debe seguir siendo no evaluable. Si esas decisiones importan a tu herramienta, pueden convertirse en expectativas explícitas. Si el equipo no está de acuerdo sobre la respuesta, la conversación pendiente es sobre la regla, no sobre la sintaxis del marco de pruebas.
Ya podemos volver a ejecutar una decisión sin abrir el modelo ni recordar qué puerta habíamos preparado ayer. Una pequeña reducción de ceremonial que estoy dispuesto a celebrar con moderación. Guarda las expectativas junto al código: cuando alguien cambie la regla, al menos tendrá que enfrentarse a una diferencia visible antes de anunciar que todo sigue funcionando exactamente igual.
Respuestas