Adelante
He leído muchas cosas antes de hacer esta pregunta, incluidas muchas preguntas relevantes aquí en SE:
- (Ingeniería de software SE) Escribir pruebas para código cuyo propósito no entiendo
- (Ingeniería de software SE) El equipo de principiantes de pruebas unitarias necesita una prueba unitaria
- (Ingeniería de software SE) Mejores prácticas para actualizar código heredado con pruebas automatizadas
- (Ingeniería de software SE) ¿Cómo realizar pruebas unitarias de sistemas heredados grandes?
- (Publicación de blog) Cómo simular su entorno de Prueba de unidad
Sin embargo, no puedo evitar sentir que aún no he rascado la picazón después de leer para pedir ayuda.
TL; DR
¿Cómo escribo pruebas unitarias para código heredado que no puedo ejecutar, simular, leer o entender fácilmente? ¿Qué pruebas de regresión son útiles para un componente que presumiblemente funciona según lo previsto?
La imágen completa
Vuelvo a ser pasante de verano nuevamente mientras estoy haciendo la transición a la escuela de posgrado. Mi tarea implica estos requisitos:
- Para un producto en particular, evalúe si nuestro equipo de software puede actualizar su versión IDE y JUnit sin perder la compatibilidad con sus proyectos existentes.
- Desarrolle pruebas unitarias para algún componente en el código Java existente (en gran medida no es Java). Queremos convencer al equipo de software de que las pruebas unitarias y TDD son herramientas invaluables que deberían utilizar. (Actualmente hay un 0% de cobertura de código).
- De alguna manera, termine los días de codificación de vaquero para un sistema crítico.
Después de obtener una copia del código fuente, intenté compilarlo y ejecutarlo, para poder entender qué hace este producto y cómo funciona. No pude Le pregunté a mis supervisores cómo me iba, y me dieron una nueva máquina independiente capaz de construirlo, incluidos los scripts de compilación que realmente funcionan. Eso tampoco funcionó porque, como deberían haber esperado, su código de producción solo se ejecuta en el sistema integrado para el que está diseñado. Sin embargo, tienen un simulador para este propósito, por lo que obtuvieron el simulador y me lo pusieron en esta máquina. El simulador tampoco funcionó. En cambio, finalmente recibí una copia impresa de una GUI para una pantalla en particular. Tampoco tienen comentarios de código en ningún lugar dentro del 700 LOC de Java, lo que hace que sea aún más difícil de entender. Además, hubo problemas al evaluar si sus proyectos eran compatibles o no con IDE más nuevos. Particularmente, su código no se cargó correctamente en la versión IDE que usan.
Mi inventario se ve así:
- NetBeans 8, 9, 10, 11
- JUEGO 4, 5
- Su código fuente para un producto en particular (incluye más de 700,000 Java LOC)
- Prácticamente no hay comentarios de código (ocasionalmente una firma)
- No hay pruebas existentes
- Una foto física de una ventana GUI
- Un documento de diseño de software (109 p.) Que no discute el componente en la imagen
Al menos tengo suficiente para escribir teóricamente pruebas que puedan ejecutarse. Entonces, probé una prueba de unidad básica en este componente mencionado. Sin embargo, no pude inicializar los objetos que tenía como dependencias, que incluían modelos, gerentes y conexiones de base de datos. No tengo mucha experiencia en JUnit más allá de las pruebas unitarias básicas, así que sígame en la siguiente sección.
Lo que aprendí de mi lectura
- Burlarse: si escribo una prueba unitaria, es probable que necesite tener variables simuladas para dependencias de producción que no puedo inicializar fácilmente
setUp
. - Todos aquí sugieren generosamente el libro "Trabajando efectivamente con código heredado" de Michael Feathers.
- Las pruebas de regresión son probablemente un buen lugar para comenzar. No creo que tenga suficiente armamento para intentar las pruebas de integración, y las pruebas de regresión proporcionarían más gratificación instantánea a nuestro equipo de software. Sin embargo, no tengo acceso a sus errores conocidos; pero, posiblemente podría preguntar.
Y ahora un intento de articular la incertidumbre que todavía tengo como una pregunta. Esencialmente, no entiendo cómo parte de escribir estas pruebas. Asumiendo que no recibo ninguna guía adicional de mis supervisores (probablemente), está en mi estadio no solo aprender qué hace este componente sino también decidir qué pruebas son realmente útiles como pruebas de regresión.
Como profesionales que han trabajado con proyectos como este por más tiempo que yo, ¿pueden ofrecer alguna guía sobre cómo escribir pruebas unitarias en este tipo de situación?
fuente
How do I write unit tests for legacy code that I can't build, run, simulate, read about, or otherwise understand?
No puedes. Al menos debe saber cuál es la salida esperada para una entrada dada.Respuestas:
Para una primera aproximación, las partes interesadas de un conjunto de pruebas son los desarrolladores / mantenedores de código. Necesitarás algo de su tiempo. Insiste en esto.
Pregúnteles sobre los problemas que enfrentan.
Pregúnteles sobre los errores que han solucionado recientemente (en los últimos años, suponiendo que este sea un proyecto largo y lento).
Tengo la impresión de que no esperas que sean amables con tu trabajo; quizás tengas razón. Pero no creo que puedas construir nada útil sin su ayuda.
Te tomarán la mano al escribir la primera prueba. Tal vez los arrastres, pero te tomarás de las manos de cualquier manera.
Una vez que tenga una prueba, con suerte será más claro cómo escribir la segunda. Si ha logrado construir algún tipo de relación, sin duda será más claro.
fuente
Asumiré que en algún momento puedes obtener el código para al menos compilar. Si ni siquiera puedes llegar tan lejos, estás haciendo un recado de tontos.
La falta de requisitos, especificaciones o capturas de pantalla adecuados no es un bloqueador para escribir pruebas. Mientras pueda leer el código fuente, puede escribir pruebas.
Si se le da permiso para refactorizar la base del código para aislar cosas como conexiones de base de datos detrás de su propia interfaz, es posible escribir algunas pruebas de unidad de recuadro negro, básicamente escribir pruebas para arrojar alguna entrada a un método y afirmar su comportamiento o salida. Obtenga pruebas que cubran cada línea de código en un método y luego haga que uno de los miembros principales del equipo revise sus pruebas.
Si no tiene permiso para refactorizar la base del código para escribir pruebas unitarias, entonces las pruebas de integración completa o las pruebas de automatización de la interfaz de usuario son su única opción. Incluso entonces, la prueba de caja negra es su mejor estrategia: arroje algo de información a la interfaz de usuario y vea cómo reacciona. Haz tus afirmaciones. Haga que un miembro senior del equipo revise sus pruebas.
En algún momento tendrá suficientes pruebas automatizadas para comenzar a refactorizar la base del código con confianza para introducir pruebas unitarias. Las pruebas de IU aseguran que los principales casos de uso de negocios funcionen, y luego puede adaptar una arquitectura que conduzca a pruebas de nivel de unidad o componente.
Otro beneficio de las pruebas de IU es que puede construir una reputación con su equipo de que entiende la base del código, lo que a su vez los hace más abiertos a la introducción de cambios, porque la prueba está en el budín. Y habrás hecho budín escribiendo pruebas de aprobación.
En breve:
Se sorprendería de lo rápido que puede aprender la vista panorámica de una aplicación de 700,000 líneas
fuente
Según la descripción del problema y sus comentarios, creo que lo mejor que puede hacer es comenzar con la API de Java e intentar construir una única prueba unitaria en torno a un método aislado.
Sin acceso al código, solo puedo darle una guía limitada, pero buscaría algo que en él a) no tenga dependencias b) no realice cambios de estado. Por ejemplo. Digamos que hay un método que toma un valor y comprueba que cae en un rango dado. Si no puede encontrar algo sin dependencias, intente algo que recupere un valor de una dependencia e intente simularlo.
Una vez que encuentre algo pequeño como esto, puede comenzar a construir pruebas. Si el método prueba un valor positivo, páselo negativo y asegúrese de que lo atrapa, etc. El problema aquí es que es posible que no sepa con certeza cuál es el comportamiento correcto. Es posible que deba pedir ayuda o buscar documentación para ello.
Es poco probable que llegue muy lejos con esto. La realidad es que escribir código para que pueda ser probado por la unidad es un arte en sí mismo. El código que no fue escrito con esto en mente puede ser difícil de imposible para la prueba unitaria.
Otra opción que puede implementarse más fácilmente es la prueba de compatibilidad binaria. Es decir, captura las entradas y salidas de un sistema y luego, para probar, alimenta esas mismas entradas y compara las salidas. Para empezar, esto no le indicará si el código es correcto o incorrecto, pero puede ayudar a detectar errores de regresión en los que las cosas cambiaron involuntariamente al realizar alguna otra modificación. Sin embargo, deberá poder ejecutar toda la aplicación para que esto suceda.
fuente