Bueno ... sí en realidad, si cada ruta "a través" del programa se prueba. Pero eso significa que todos los caminos posibles a través del espacio completo de todos los estados posibles que puede tener el programa, incluidas todas las variables. Incluso para un programa muy simple compilado estáticamente, por ejemplo, un antiguo analizador de números de Fortran, eso no es factible, aunque puede ser al menos imaginable: si tiene solo dos variables enteras, básicamente está tratando con todas las formas posibles de conectar puntos en una cuadrícula bidimensional; En realidad, se parece mucho a un vendedor ambulante. Para n tales variables, estás tratando con un espacio dimensional n , por lo que para cualquier programa real, la tarea es completamente imposible de encontrar.
Peor: para cosas serias, usted tiene no solo un número fijo de variables primitivas, pero crea variables sobre la marcha en llamadas a funciones, o tiene variables de tamaño variable ... o algo por el estilo , como sea posible en un lenguaje completo de Turing. Eso hace que el espacio estatal sea infinito-dimensional, destruyendo todas las esperanzas de una cobertura total, incluso con un equipo de prueba absurdamente poderoso.
Dicho esto ... en realidad las cosas no son tan sombrías. Es posible probar programas completos para que sean correctos, pero tendrás que renunciar a algunas ideas.
Primero: es muy recomendable cambiar a un lenguaje declarativo. Los lenguajes imperativos, por alguna razón, siempre han sido, con mucho, los más populares, pero la forma en que combinan los algoritmos con las interacciones del mundo real hace que sea extremadamente difícil decir lo que quiere decir con "correcto".
Mucho más fácil en lenguajes de programación puramente funcionales : estos tienen una clara distinción entre las propiedades interesantes reales de matemática funciones , y las interacciones difusas del mundo real de las que realmente no se puede decir nada. Para las funciones, es muy fácil especificar el "comportamiento correcto": si para todas las entradas posibles (de los tipos de argumentos) sale el resultado deseado correspondiente, la función se comporta correctamente.
Ahora, dices que todavía es intratable ... después de todo, el espacio de todos los argumentos posibles es en general también infinito-dimensional. Cierto, aunque para una sola función, incluso las pruebas de cobertura ingenuas lo llevan mucho más lejos de lo que podría esperar en un programa imperativo. Sin embargo, hay una herramienta increíblemente poderosa que cambia el juego: cuantificación universal / polimorfismo paramétrico . Básicamente, esto le permite escribir funciones en tipos de datos muy generales, con la garantía de que si funciona para un ejemplo simple de los datos, funcionará para cualquier entrada posible.
Al menos en teoría. No es fácil encontrar los tipos correctos que son realmente tan generales que puede probarlo por completo. Por lo general, necesita un lenguaje de tipo dependiente , y estos tienden a ser bastante difíciles de usar. Pero escribir en un estilo funcional solo con polimorfismo paramétrico aumenta tu "nivel de seguridad" enormemente. ¡No necesariamente encontrarás todos los errores, pero tendrás que esconderlos bastante bien para que el compilador no los detecte!