Tengo un software bastante grande que toma ciertos tipos de archivos y los visualiza / crea una gran cantidad de botones para la manipulación de la imagen trazada. Siento que estoy encontrando errores / piezas de código que en realidad no funcionan una vez a la semana, pero me cuesta entender cómo puedo escribir pruebas para este software.
Entiendo cómo las pruebas son importantes para proyectos como bibliotecas y API, simplemente escribe pruebas que usan estas funciones.
¿Pero qué pasa con el software de visualización? Parece requerir un enfoque diferente debido a los elementos visuales involucrados.
¿Necesito escribir un programa de prueba o un arnés de prueba que se ejecute y llame manualmente a todas las operaciones, siempre que pueda usarlas en los datos?
¿Qué enfoque debo usar para comenzar a escribir pruebas para validar que reparé los errores y alertarme si el código se rompe nuevamente?
Hay una pregunta relacionada pero no duplicada sobre cuándo debe realizar la prueba unitaria. Como estoy descubriendo errores, quiero escribir pruebas para ayudar a evitar que el software retroceda nuevamente.
fuente
Todo tiene una interfaz. Cuando me pongo el sombrero de prueba, uso una visión del mundo específica para escribir una prueba:
En su caso, su sistema tiene tres partes principales:
Por cierto, eso me parece mucho la arquitectura original del Modelo-Vista-Controlador. Idealmente, estos tres elementos exhiben un acoplamiento flojo, es decir, usted define límites claros entre ellos con interfaces bien definidas (y por lo tanto bien comprobables).
Una interacción compleja con el software puede traducirse en pequeños pasos que pueden expresarse en términos de los elementos del sistema que estamos probando. Por ejemplo:
Esto parece ser fácil de probar manualmente y difícil de probar automatizado. Pero traduzcamos esa historia a nuestro sistema:
Agrupados por componente, terminamos con las siguientes propiedades para probar:
Si no descomponemos el problema de las pruebas en subpruebas más pequeñas, las pruebas se vuelven realmente difíciles y realmente frágiles. La historia anterior también podría implementarse como "cuando cargo un archivo específico y establezco el control deslizante en un valor específico, se representa una imagen específica". Esto es frágil ya que se rompe cuando cambia cualquier elemento del sistema.
Las pruebas granulares también tienen la gran ventaja de que me permiten evolucionar el sistema sin temor a romper ninguna característica. Dado que todo el comportamiento requerido se mide mediante un conjunto de pruebas completo, las pruebas me notificarán si algo se rompe. Como son granulares, me señalarán el área del problema. Por ejemplo, si cambio accidentalmente la interfaz de cualquier componente, solo las pruebas de esa interfaz fallarán y no cualquier otra prueba que utilice indirectamente esa interfaz.
Si se supone que la prueba es fácil, esto requiere un diseño adecuado. Por ejemplo, es problemático cuando cableo componentes en un sistema: si quiero probar la interacción de un componente con otros componentes en un sistema, necesito reemplazar esos otros componentes con trozos de prueba que me permiten iniciar sesión, verificar, y coreografiar esa interacción. En otras palabras, necesito algún mecanismo de inyección de dependencia, y se deben evitar las dependencias estáticas. Al probar una interfaz de usuario, es de gran ayuda cuando esta interfaz de usuario es programable.
Por supuesto, la mayor parte de eso es solo una fantasía de un mundo ideal donde todo está desacoplado y fácilmente comprobable y los unicornios voladores transmiten amor y paz ;-) Si bien cualquier cosa es fundamentalmente comprobable, a menudo es prohibitivamente difícil hacerlo, y es mejor hacerlo usos de tu tiempo. Sin embargo, los sistemas se pueden diseñar para que sean comprobables y, por lo general, incluso los sistemas independientes de las pruebas cuentan con API o contratos internos que se pueden probar (si no, apuesto a que su arquitectura es una mierda y ha escrito una gran bola de barro). En mi experiencia, incluso pequeñas cantidades de pruebas (automatizadas) producen un aumento notable de la calidad.
fuente
Comience con un archivo conocido que produzca una imagen esperada. Verifica cada píxel. Cada uno debe tener un valor esperado para un archivo de prueba conocido, hecho a mano. Debería tener una imagen de salida esperada para compararla. Cualquier cosa que esté "desactivada" significa un error en su código.
Expanda su archivo de prueba para que la imagen de salida cambie y llegue a todas las funciones de su software.
Las secuencias de comandos serían útiles para ese tipo de pruebas de caja negra. Un script simple que ejecuta la última versión de su software para la entrada conocida y la salida esperada.
Las pruebas unitarias, por otro lado, deben ser pruebas de caja blanca donde se toma la menor cantidad posible de software, generalmente una función o lo que sea, y ver si se comporta como espera. Podrías ver qué color de píxel devuelve, o lo que sea. En este caso, su código se comporta como una biblioteca, con API para todas las demás secciones de su código.
Si todo está guardado en un archivo .c con toda la funcionalidad incorporada
main()
, entonces tienes problemas más grandes que la forma de probar.fuente