Testability

Intención y evidencia

Testability describe qué tan fácil es obtener evidencia confiable y suficientemente rápida sobre el comportamiento del sistema, y localizar causas cuando algo falla. La facilidad comprende preparar condiciones, ejecutar comportamientos, observar efectos e interpretar resultados. Tener muchos tests no responde por sí solo a esa pregunta.

El informe SEI Testing a Software Product Line, sección 2.6 relaciona testability con revelar defectos y reducir esfuerzo para localizarlos, usando controllability y observability. Es un fundamento para analizar qué permite comprobar la arquitectura, no una instrucción de exponer indiscriminadamente todo estado interno.

Importa porque la distribución de responsabilidades, efectos y dependencias condiciona el costo de descubrir errores. Si validar un cálculo obliga a levantar todo el producto y esperar a un proveedor remoto, un cambio pequeño puede generar feedback lento e incierto. quality-attribute-scenarios ayuda a identificar qué evidencia necesitamos y en qué entorno.

Controllability y observability

Controllability permite colocar el artifact en estados relevantes y suministrarle entradas. Incluye configurar una condición inicial, elegir el resultado de una dependencia y provocar un fallo previsto. No significa reemplazar el comportamiento que se desea comprobar por el resultado esperado.

Observability, en este contexto de testing, permite inspeccionar salidas, estado o efectos necesarios para evaluar el comportamiento. El test necesita reconocer una respuesta equivocada y disponer de información para investigar su causa. Esto es distinto del cuerpo operacional completo de logs, metrics y traces, aunque ciertos mecanismos puedan servir a ambos.

En nuestro ejemplo propio, calcular un pago requiere una política de precio y una respuesta del proveedor. Un test puede controlar rechazo y verificar que no se registre un cobro exitoso. Comprobar solamente que «se llamó al proveedor» deja abierta la corrección del resultado, del importe y de los efectos posteriores.

La evidencia exige un criterio de evaluación, u oracle: qué resultado sería correcto dadas las condiciones. Un output observable sin expectativas significativas no revela un defecto. Tampoco conviene romper encapsulación, exponer datos sensibles o habilitar puertas de administración en producción únicamente para facilitar una prueba.

Estímulos, entornos y medidas

Los estímulos incluyen una modificación, una regresión reportada o una necesidad de comprobar un comportamiento antes de entrega. El artifact puede ser una regla, caso de uso, adaptador o conjunto de capacidades. Los entornos van desde ejecución local hasta integración y preproducción, con distinto control y fidelidad.

La respuesta prepara estados, ejecuta casos relevantes y presenta resultado y diagnóstico. Medidas útiles incluyen tiempo de preparación y ejecución, estabilidad entre corridas, esfuerzo para construir condiciones y tiempo para localizar el límite responsable. Deben precisar comportamiento, datos y entorno: medir únicamente duración omite si las pruebas detectan el error que importa.

Code coverage informa qué código ejecutaron las pruebas, no basta para medir testability ni corrección. Una rama ejecutada con una assertion irrelevante puede conservar un defecto. Usar coverage como señal complementaria requiere entender su alcance; aumentar porcentaje no sustituye criterios sobre comportamiento.

Dependencias controladas y fronteras

Payment use case
    ↓ application port
Payment provider adapter
    ↓
External provider

En este caso propio, el test del use case controla el contrato mediante un colaborador conocido. Puede evaluar rechazo, resultado incierto o respuesta válida sin depender de una cuenta real. La prueba del adaptador debe comprobar traducción y semántica contra una integración representativa; su evidencia responde otra pregunta.

Cockburn muestra que los ports admiten adaptadores tecnológicos y de prueba. ports-and-adapters puede aislar una colaboración difícil de controlar. clean-architecture orienta dependencias para proteger políticas; Martin describe su intención de probar reglas sin UI, database o servidor.

Ninguno garantiza alta testability. Si un port expone un objeto remoto con estado global, o el núcleo instancia infraestructura directamente, el control esperado puede desaparecer. Una arquitectura sobreabstracta también puede exigir numerosos fixtures y traducciones sin aportar evidencia representativa. Revisar el comportamiento y las dependencias reales importa más que verificar nombres de carpetas.

Seams, dobles y acoplamiento de pruebas

architectural-tactics permite formular una decisión enfocada: introducir un punto de sustitución para controlar una dependencia relevante. El efecto esperado es reproducir condiciones con menor costo; el trade-off son indirection, gestión contractual y mantenimiento del colaborador de prueba.

Los dobles no son todos mocks. Fowler distingue sustituciones y verificación de estado o interacciones en Mocks Aren’t Stubs, y examina cómo expectations detalladas pueden acoplar pruebas a la implementación. En nuestro ejemplo, exigir una secuencia incidental de llamadas puede romper al refactorizar aunque el comportamiento siga siendo correcto.

Controlar todas las colaboraciones hasta no ejecutar ninguna regla significativa produce confianza aparente. Por otra parte, una interacción puede ser parte del contrato: impedir un segundo cobro sí merece evidencia. La revisión identifica qué obligación verifica cada expectation y qué cambio legítimo debería tolerar.

Demasiados seams pueden ampliar la API interna y dificultar comprensión. El mecanismo se justifica si permite ejercitar una condición necesaria, con evidencia que compense ese costo. «Mock everything» no es una definición de arquitectura testable.

Evidencia en distintos niveles

Unit tests pueden ofrecer feedback focalizado sobre reglas. Integration tests comprueban acuerdos entre piezas, incluyendo mappings y constraints. System tests observan recorridos más amplios y condiciones de ensamblaje. Son niveles complementarios; la arquitectura no debería obligar a elegir entre aislamiento máximo y una única prueba gigantesca.

El sitio de Continuous Delivery sobre arquitectura enfatiza descubrir defectos sin depender siempre de entornos integrados complejos. Para el caso de pagos, eso permite comprobar numerosas reglas localmente, sin convertir el doble en evidencia suficiente sobre autenticación, transacciones o respuestas del proveedor real.

Mayor fidelidad puede descubrir incompatibilidades que una ejecución aislada omite, con costo de infraestructura, preparación y tiempo. La decisión necesita relacionar riesgo con evidencia: una regla aritmética y un protocolo externo no requieren exactamente el mismo entorno. quality-attribute-trade-offs permite discutir esa tensión sin imponer una proporción universal de tests.

Determinismo y condiciones variables

Tiempo, randomness, concurrencia, servicios externos y consistencia eventual pueden cambiar resultados entre corridas. Fowler analiza reloj, aislamiento, asincronía y dependencias remotas en Eradicating Non-Determinism in Tests. Sustituir el reloj o controlar una dependencia permite reproducir ciertas condiciones; también exige comprobar que el sustituto representa obligaciones relevantes.

En nuestro ejemplo, una tarifa vence en una fecha. Un reloj controlable permite probar ambos lados del límite sin esperar. Datos iniciales independientes evitan que otro test altere el resultado. Una semilla registrada puede reproducir generación aleatoria, pero no fija automáticamente la planificación de threads.

Para concurrencia y consistencia eventual pueden necesitarse coordinación explícita, espera acotada por una condición observable y exploración de interleavings. Dormir un tiempo arbitrario puede pasar en una máquina y fallar en otra. Una corrida reproducible ayuda a diagnosticar; no prueba ausencia de carreras ni cubre todos los estados.

Escenario: cambio en cálculo de pagos

CampoEscenario propio
SourceDeveloper y pipeline de CI.
StimulusSe modifica el componente de cálculo de pagos.
ArtifactFrontera de pricing y cálculo de pagos, con sus contratos de colaboración.
EnvironmentEntorno automatizado de preproducción, datos controlados y condiciones iniciales conocidas.
ResponseLas pruebas relevantes ejercitan el comportamiento con dependencias controladas y exponen fallos con evidencia diagnóstica.
Response MeasureTerminan dentro del presupuesto temporal acordado y permiten identificar la frontera responsable sin requerir sistemas externos no relacionados.

Para evaluarlo se acuerdan casos relevantes, criterio de corrección, datos, presupuesto y diagnóstico suficiente. Si falla la preparación del entorno, debe poder distinguirse de un defecto del cálculo. Una persona debe poder investigar usando entradas y resultado observado, sin deducir la causa exclusivamente de una assertion genérica.

El escenario no elimina pruebas reales de integraciones relacionadas. Para agregar otro proveedor, podemos validar decisiones del use case con un doble y reservar pruebas representativas para el adaptador. Esa división conserva feedback rápido y declara qué incertidumbre permanece.

Relaciones y errores frecuentes

fitness-functions evalúa expectativas arquitectónicas seleccionadas. Un unit test puede contribuir a esa evaluación sin convertirse automáticamente en ella; testability facilita obtener evidencia y diagnóstico, pero no es el mecanismo ni prueba de arquitectura correcta. Pruebas y evaluaciones manuales pueden aportar coberturas complementarias.

legacy-systems contextualiza la definición de trabajo de Feathers centrada en código sin tests. Aquí importa la capacidad de obtener evidencia para un cambio real: agregar pruebas representativas puede reducir incertidumbre sin resolver por sí solo consumidores ocultos, contratos o límites de plataforma.

modifiability necesita confianza para modificar sin regresiones; evolvability necesita evidencia durante transiciones; deployability necesita comprobar combinaciones de versiones que llegarán a ejecución. Una frontera estable puede ayudar a todas y aun introducir costos contractuales.

Tests verdes solo respaldan comportamientos y entornos ejercitados. Muchas pruebas frágiles, coverage alto o un profile conocido no demuestran facilidad para obtener evidencia nueva. Evaluar testability requiere observar preparación, control, fidelidad, diagnóstico y costo frente al escenario que importa.