¿Cómo mantener estable el tronco cuando las pruebas toman mucho tiempo?

9

Tenemos tres conjuntos de suites de prueba:

  • Una suite "pequeña", que tarda solo un par de horas en ejecutarse
  • Una suite "mediana" que toma varias horas, generalmente se ejecuta todas las noches (todas las noches)
  • Una suite "grande" que tarda una semana o más en ejecutarse

También tenemos un conjunto de conjuntos de pruebas más cortos, pero no me estoy centrando en ellos aquí.

La metodología actual es ejecutar el conjunto pequeño antes de cada confirmación en el enlace troncal. Luego, la suite mediana funciona todas las noches, y si por la mañana resultó que falló, tratamos de aislar cuál de las confirmaciones de ayer fue la culpable, revertir esa confirmación y volver a intentar las pruebas. Se realiza un proceso similar, solo en una frecuencia semanal en lugar de nocturna, para la suite grande.

Desafortunadamente, la suite mediana falla con bastante frecuencia. Eso significa que el tronco a menudo es inestable, lo cual es extremadamente molesto cuando desea realizar modificaciones y probarlas. Es molesto porque cuando salgo del baúl, no puedo saber con certeza si es estable, y si una prueba falla, no puedo saber con certeza si es mi culpa o no.

Mi pregunta es, ¿hay alguna metodología conocida para manejar este tipo de situaciones de una manera que deje el tronco siempre en la mejor forma? por ejemplo, "comprometerse en una rama especial de precompromiso que luego actualizará periódicamente el tronco cada vez que pase la noche"

¿Importa si es un sistema de control de fuente centralizado como SVN o uno distribuido como git?

Por cierto, soy un desarrollador junior con una capacidad limitada para cambiar las cosas, solo estoy tratando de entender si hay una manera de manejar este dolor que estoy experimentando.

Roble
fuente
66
No tengo idea en qué software está trabajando, pero un pequeño conjunto de pruebas que lleva horas ejecutar es algo de WTF. Si corrieran más rápido, esto sería más fácil, ¿no hay forma de optimizar sus pruebas?
Benjamin Bannier el
2
¿Qué tiene de "extremadamente molesto" que el tronco sea inestable? No sé si lo sabe, pero una de las estrategias de ramificación más populares incluso se llama tronco inestable
mosquito
1
Hay muchas formas de optimizar un conjunto de pruebas (como para cualquier otro software). No tengo idea de por qué los suyos tardan tanto, pero es posible que, por ejemplo, pueda reutilizar parte del entorno de prueba o simplemente usar mejores algoritmos / estructuras de datos cuando se ejecuta (la creación de perfiles ayuda). También puede ser que nadie se haya tomado el tiempo para identificar muestras representativas y simplemente pruebe cada entrada / salida posible con alguna referencia. Quizás su sistema de compilación le permita codificar dependencias de prueba de código para que no necesite ejecutar el conjunto completo. Y sé que esta no era tu pregunta, es por eso que hice un comentario, no una respuesta.
Benjamin Bannier
1
... hmm, es probable que su mejor opción mejore las pruebas y el registro de aplicaciones para que sea más fácil encontrar el motivo de la falla. De esta manera, uno tendría que encontrar y corregir la causa de la falla en lugar de desperdiciar esfuerzos en "investigaciones policíacas" en busca de quién, cuándo y por qué cambió en particular línea de código ...
mosquito
1
@honk Algunas pruebas tardan mucho tiempo en ejecutarse. Trabajo para una empresa que fabrica equipos de adquisición de datos y nuestra prueba de prueba "parcial" dura aproximadamente una hora. Las pruebas necesitan hacer varios tipos de mediciones y eso solo lleva tiempo.
Velociraptors

Respuestas:

1

La única forma de corregir la causa raíz de la inestabilidad es desacoplar el código para que los cambios estén más aislados, como han sugerido otras respuestas.

Sin embargo, como desarrollador individual, si desea una construcción más estable para que trabaje personalmente, es relativamente fácil de resolver. En lugar de trabajar fuera de la punta, solo extrae la última compilación que pasó el conjunto de pruebas durante la noche en su árbol de trabajo. Si puede crear ramas de características para cada cambio, bifurquese de la última versión estable.

Sí, su árbol estará retrasado unos días, pero la mayoría de las veces eso no importa. Haga su trabajo contra la compilación estable, para que sepa que sus cambios son los que rompieron cualquier prueba, luego, antes de registrarse, actualice a la última versión y realice su integración normal. Luego, después de registrarse, vuelva a la última versión estable.

Todavía tiene que hacer el trabajo de integración desordenado, pero lo que me gusta de este método es que aísla el trabajo de integración en un momento más conveniente para mí y me da una base de código estable para el desarrollo cuando no es conveniente. Tengo una idea mucho mejor cuando son mis cambios los que probablemente rompieron la compilación frente a los de otra persona.

Karl Bielefeldt
fuente
1
-1 trabajar desde sucursales es una opción viable, pero recomendarlo sin sugerencias de prueba podría hacer más daño que bien. Solo las pruebas pueden mostrar si es factible para un proyecto específico o no. Por ejemplo, en un proyecto que realicé hace aproximadamente 2 años, una prueba de este tipo demostró que trabajar desde sucursales requería ~ 7 veces más esfuerzos en comparación con el tronco inestable
mosquito
Gracias Karl! Si bien esto no es lo que esperaba aprender, este es un enfoque muy práctico que podría ayudarme a resolver el problema en cuestión. Y estoy de acuerdo en que trabajar unos días detrás del tronco raramente causará problemas de integración.
Roble
12

Sé que está tratando de evitar esto, pero la idea real aquí es darse cuenta de que algo está muy mal con su base de código: ¡necesita ejecutar un conjunto completo de pruebas que lleva una semana solo para asegurarse de que su código sea estable!

La forma más ventajosa de solucionar este problema es comenzar a separar la base de código y las pruebas en subunidades (independientes).
Hay grandes ventajas en esto:

  • Las pruebas para cada una de esas unidades se ejecutarán más rápido (simplemente hay menos de ellas), y no se romperán si algo sale mal en una de las unidades independientes o aguas abajo.
  • Una prueba fallida se identificará con una unidad en particular, lo que hará que sea mucho más fácil encontrar la fuente del problema.
  • Puede separar las ubicaciones de VCS de las diferentes unidades para que su rama "estable" pueda ser una combinación de la última compilación probada con éxito de cada unidad, de modo que una o dos unidades rotas no desestabilicen su versión "estable" .

En el reverso, el manejo de su estructura VCS se volverá más complicado, pero en una semana completa para su prueba completa, ¡creo que puede soportar el dolor!

Todavía recomiendo usar una estrategia de sucursales "estable" y de "desarrollo" de una forma u otra, pero hay muchas maneras de hacerlo y puede elegir la que mejor funcione para su organización (meta-repositorios con revisiones fijas que apuntan a repositorios separados para cada unidad, una rama estable y una rama de desarrollo, ramas de características ...)

Joris Timmermans
fuente
1
Nunca dije que la prueba grande es una prueba atómica, es un conjunto de pruebas . Cuando un desarrollador individual realiza una modificación en el elemento X, ejecuta las pruebas relevantes para X, sin importar de qué conjunto de pruebas se originaron. Esto se suma a la prueba semanal, que se realiza para garantizar que un cambio en un lugar no afecte inesperadamente a otro. Pero usted hace un punto interesante de que al menos separar las cosas de esta manera ayudará a acelerar las pruebas para módulos específicos, mientras mantiene el riesgo aproximadamente al mismo nivel.
Roble
2
@oak - Bueno, en cierto modo, la suite ES atómica si se ejecuta todo es la única forma en que realmente está seguro de que el código es estable, pero si hace un buen punto, he editado mi respuesta.
Joris Timmermans el
44
Tenemos enormes conjuntos de pruebas para nuestros compiladores, algunos de los cuales tardan varios días en ejecutarse, y no creo que sea poco común para un software tan complejo como un compilador de C ++. No es que la suite defina lo que se debe considerar como "estable", sino que hay millones de diferentes esquinas de generación de código que es imposible probarlas todos los días.
JesperE
1
@JesperE: eso es comprensible si el enorme conjunto de pruebas no define "estable" pero es una prueba de cordura gigantesca. No esperaría que la suite completa (o incluso la suite mediana) fallara muy a menudo.
Joris Timmermans el
1

Para SVN, no sé acerca de algo como "pre-commit". Creo que es probable que produzca confirmaciones y retrocesos cuando la prueba falla. Como dice doc-brown, la única forma es comprometerse en una rama temporal y fusionarla con el tronco más adelante.

Usando uno distribuido como git o mercurial, creo que sería posible. Usando un repositorio de "prueba" y un repositorio "estable". Presiona el representante de prueba, lo prueba todas las noches y, si todo funciona bien, pasa de prueba a estable. De lo contrario, revierte el representante de prueba. No estoy seguro de cómo se vería el historial de versiones cuando se pasa de la prueba a la estable, pero creo que es posible excluir las cosas rotas al hacer esto. Experimentar un poco primero sería lo más seguro.

Una alternativa también sería probar el tronco local de cada persona todas las noches. Luego, las personas con pruebas aprobadas pueden enviarlo al servidor central por la mañana.

dagnelies
fuente
1

En mi humilde opinión esto no tiene nada que ver con el VCS que está utilizando. El uso de una rama "bajo prueba" puede ser una solución, que también puede realizarse con VCS centralizado o distribuido. Pero honestamente, creo que lo mejor en su situación es tratar de optimizar el conjunto de pruebas medianas (parece que contiene las pruebas más importantes) para que se ejecute mucho más rápido, de modo que pueda usarlo para pre-commit-to-trunk pruebas, tal como lo hace ahora con su "suite pequeña".

Doc Brown
fuente
Aquí estoy preguntando sobre la metodología, es decir, ¿hay una manera común de lidiar con tal situación? Supongamos, al menos por el bien de esta discusión, que las pruebas no pueden optimizarse más allá de lo que ya son.
Roble
@Oak: alguien aquí (¿tú?) Votó en contra de mi respuesta, pero a veces las cosas que no quieres escuchar son las únicas que ayudarán. Como puede ver en la discusión debajo de su pregunta, otros sugirieron lo mismo, por lo que mi sugerencia no parece ser tan mala en absoluto.
Doc Brown
+1, esta es la respuesta correcta. La verdadera pregunta del OP es "Ayuda, me estoy ahogando, ¿qué metodología puedo usar para ayudarme?" y la respuesta es que realmente la metodología no es de lo que debería preocuparse.
MrFox
1

Las pruebas del medio que fallaron: ¿Es cierto que la mayoría de las veces las mismas pruebas fallan?

Si hay una falla, ¿hay siempre las mismas pruebas relacionadas que fallan?

Si es cierto: puede seleccionar selectivamente algunas pruebas medianas que a menudo fallan (una prueba para cada clase de error) y ejecutarlas dentro del conjunto pequeño.

¿La mayoría de las pruebas son pruebas de integración que usan una base de datos real? Si es así, ¿es posible reemplazarlos con una prueba de unidad que tenga una base de datos simulada?

k3b
fuente
1

Necesita hacer que sus pruebas se ejecuten más rápido, no hay otra forma de cuadrar este círculo.

Considere el problema: desea asegurarse de que cuando salga, tenga un código que funcione. Claro, puede retrasar las confirmaciones y hacer ramificaciones hasta antes del lanzamiento, pero eso solo retrasará la aparición del problema hasta la integración. Como en, ¿tendrá que ejecutar la suite de una semana después de cada fusión? La metodología no es la solución, la solución es puramente técnica.

Esto es lo que sugiero:

1) Haga que las pruebas sean lo más atómicas posible y maximice la reutilización del entorno.

2) Obtenga una granja de prueba-suite para ejecutarlos. Si en lugar de 8 módulos grandes terminas con 50, puedes girar un montón de instancias puntuales de Amazon EC2 y ejecutar todo el conjunto en paralelo. Estoy seguro de que esto costará algo de dinero, pero ahorrará grandes cantidades de tiempo de desarrollador.

Señor Fox
fuente
0

Lo clave que está dando por sentado en su pregunta es que todos los commits deben pasar las pruebas. Si bien esta es una buena regla a seguir y parece tener sentido, a veces no es práctica. Su caso es un ejemplo (aunque MadKeithV hace un punto), y me imagino que mantener una rama VCS tan prístina podría ser difícil si no hay suficiente cooperación entre los desarrolladores.

En realidad, lo que quiere es saber de alguna manera qué confirmaciones pasan o no. Una "rama previa a la confirmación", como usted sugirió, funcionaría, pero eso podría requerir un esfuerzo adicional de los desarrolladores cuando realizan las confirmaciones, lo que puede ser difícil de vender.

Un enfoque similar que podría ser más fácil es dejar el tronco para que las personas se rompan como quieran, y tener una rama para los compromisos que no están rotos. Una secuencia de comandos automatizada podría pasar por confirmaciones a medida que se realizan en el tronco, ejecutar las pruebas en ellas y agregarlas a la rama si pasan.

O podría ser absurdamente simplista y tener un script que enumere las confirmaciones de paso en un archivo de texto (que puede o no ser controlado por la versión).

O tenga un sistema por lotes que acepte solicitudes de ramas / revisiones para probar (desde cualquier parte del árbol), y las pruebe y las confirme en el tronco (u otra rama) si pasan.

Michael Slade
fuente