Estrategias para pruebas unitarias y desarrollo basado en pruebas

16

Soy un gran defensor del desarrollo basado en pruebas en informática científica. Su utilidad en la práctica es asombrosa, y realmente alivia los problemas clásicos que los desarrolladores de códigos conocen. Sin embargo, existen dificultades inherentes al probar códigos científicos que no se encuentran en la programación general, por lo que los textos TDD no son terriblemente útiles como tutoriales. Por ejemplo:

  • En general, no conoce una respuesta exacta para un problema complejo dado a priori, entonces, ¿cómo puede escribir una prueba?

  • El grado de paralelismo cambia; Recientemente encontré un error en el que el uso de tareas MPI como múltiplo de 3 fallaba, pero un múltiplo de 2 funcionó. Además, los marcos de prueba comunes no parecen ser muy compatibles con MPI debido a la naturaleza misma de MPI: debe volver a ejecutar un binario de prueba para alterar la cantidad de tareas.

  • Los códigos científicos a menudo tienen muchas partes estrechamente acopladas, interdependientes e intercambiables. Todos hemos visto el código heredado, y sabemos lo tentador que es renunciar a un buen diseño y usar variables globales.

  • A menudo, un método numérico puede ser un "experimento", o el codificador no comprende completamente cómo funciona y está tratando de entenderlo, por lo que es imposible anticipar resultados.

Algunos ejemplos de pruebas que escribo para código científico:

  • Para los integradores de tiempo, use un ODE simple con una solución exacta y pruebe que su integrador lo resuelva con una precisión dada, y el orden de precisión es correcto al probar con diferentes tamaños de pasos.

  • Pruebas de estabilidad cero: verifique que un método con límite 0 / condiciones iniciales permanezca en 0.

  • Pruebas de interpolación: dada una función lineal, asegúrese de que una interpolación sea correcta.

  • Validación heredada: aísle un fragmento de código en una aplicación heredada que se sabe que es correcta y extraiga algunos valores discretos para usarlos en las pruebas.

Todavía a menudo surge que no puedo entender cómo probar adecuadamente un fragmento de código dado, aparte de la prueba y error manual. ¿Puede proporcionar algunos ejemplos de pruebas que escriba para código numérico y / o estrategias generales para probar software científico?

Aurelio
fuente
¿Podría, por favor, aclarar lo que quiere decir con pruebas de interpolación?
Dmitry Kabanov

Respuestas:

8

Método de soluciones fabricadas .

Verificar mediante estudios de refinamiento que el método logra el orden teórico de precisión.

Conservación de la respuesta. Reproducción de soluciones a nivel de bits y norma.

Bill Barth
fuente
Quería mencionar MMS en la publicación original; es bueno para la verificación de código, pero desde una perspectiva de prueba de unidad no tiene ningún valor. Si esas pruebas fallan, no proporciona pistas sobre dónde o por qué.
Aurelius
3
2×2×2
Gran parte de la literatura que he visto sobre MMS son básicamente soluciones globales, por ejemplo, para problemas de CFD, una solución fabricada podría ser un análisis aerodinámico. Cuando esta prueba falla, en el mejor de los casos, ha reducido el culpable a 5,000 líneas de código, por lo que no tiene ningún valor para TDD: no tiene idea de dónde se produce la falla real. Estoy de acuerdo en que un problema de 2x2x2 es extremadamente valioso, y personalmente los uso mucho. Pero es bastante común que encuentre problemas que solo aparecen con sistemas más grandes; En realidad, encontré un error del compilador ifort recientemente que solo se manifestó en grandes problemas.
Aurelius
@Aurelius: No hay discusión aquí. Debe tener una variedad de pruebas y ejecutarlas con frecuencia.
Bill Barth
@Aurelius En su valor nominal, MMS no es una prueba unitaria, sino una prueba funcional o de aceptación (es decir, de todo el sistema). Sin embargo, los códigos a menudo tienen etapas separadas (o se pueden dividir en ellas). por ejemplo, advección, presión, viscosidad. Entonces se podría probar solo una de estas etapas (una "unidad"). Del mismo modo, un código podría probarse sin un BC y luego con uno. Un amigo hizo su doctorado en pruebas unitarias, y calculó que el mayor beneficio era que te obligaba a dividir tu programa en unidades, por lo que puede probarse en unidades ... tal vez esto sea más aplicable aquí de lo que parece al principio (y en otros aspectos no lo sé).
hiperpallium
6

Bill ya ha enumerado algunos métodos que abordan sus inquietudes.

Al abordar su tercer punto, no, no hay razón para introducir un fuerte acoplamiento entre las partes. Todo lo contrario: si sus funciones o clases tienen interfaces bien definidas, será mucho más fácil intercambiar, por ejemplo, un solucionador lineal por otro, o un esquema de paso de tiempo. Simplemente resístalo y podrás probar estos componentes por separado. Lo hemos hecho con deal.II durante décadas.

Para su cuarto punto: si su método es un experimento, sus experimentos con el método constituyen una prueba. Mientras no tenga un análisis, tendrá que tomar estos resultados de prueba como los mejores disponibles. Pero por lo general, tiene una expectativa, por ejemplo, para el orden de un método, o sabría que es exacto para una cierta clase de soluciones, por ejemplo, polinomios hasta cierto grado. La verificación de estos debe ser parte de sus experimentos y, a medida que el análisis mejora, se pueden agregar pruebas.

Guido Kanschat
fuente
1
Para agregar a la respuesta de Guido, la experiencia de la que habla está codificada en las ~ 3,000 pruebas que ejecutamos en deal.II después de cada cambio: dealii.org/developer/development/… . Sobre la pregunta de qué hacer si no sabe la respuesta exacta: escriba una prueba de todos modos y deje que compare la respuesta hoy con la respuesta de ayer (o cada vez que escribió la prueba). Tener una forma de detectar cambios en la salida de un código es valioso incluso si no sabe si hicieron que la respuesta fuera incorrecta o si corrigieron una respuesta incorrecta anterior.
Wolfgang Bangerth
3

Recientemente encontré esta tesis sobre TDD en Ciencias Computacionales. Todavía no lo he leído, así que no tengo idea de si es bueno, pero espero que pueda ser de alguna ayuda.

http://cyber.ua.edu/files/2014/12/u0015_0000001_0001551.pdf

revistas
fuente
1
Leí un poco de la introducción y las conclusiones, y suponiendo un nivel de calidad a la par con la tesis doctoral estándar, esto explica el proceso (de una manera de alto nivel) y proporciona mediciones reales en cuanto a su efectividad. Creo que este es un gran hallazgo.
Godric Seer
El enlace está muerto. Quiso decir: Nanthaamornphong, A. "La efectividad del desarrollo basado en pruebas y técnicas de refactorización en el desarrollo de software de ingeniería y ciencia computacional". PhD diss., Uni. Alabama (2014).
AlQuemist