Cuando se realiza una integración continua ejecutando las pruebas en cada confirmación, una práctica recomendada común es hacer que todas las pruebas pasen en todo momento (también conocido como "no rompa la compilación").
Encuentro algunos problemas con eso:
Por ejemplo, uno no puede ayudar a un proyecto de código abierto creando pruebas correspondientes a tickets. Sé que si propongo una Solicitud de extracción a un proyecto de código abierto que contenga una prueba fallida, la compilación se marcará como fallida y el proyecto no querrá que se fusione en su repositorio porque "rompería la compilación".
Y no creo que sea malo tener pruebas fallidas en su repositorio , es como tener problemas abiertos en su rastreador. Estas son solo cosas que esperan ser reparadas.
Lo mismo ocurre en una empresa. Si trabaja con TDD, no puede escribir pruebas, comprometerse y luego escribir el código lógico que cumple la prueba. Eso significa que si he escrito 4-5 pruebas en mi computadora portátil, no puedo enviarlas antes de irme de vacaciones. Nadie puede recuperar mi trabajo. Ni siquiera puedo "compartirlos" con un colega, excepto enviándolos por correo electrónico, por ejemplo. También evita trabajar con una persona que escribe las pruebas y la otra que escribe el modelo.
Todo eso para decir, ¿estoy haciendo mal uso / malentendido el proceso de construcción / integración continua? Me parece que "pasar" / "no pasar" es un indicador demasiado limitado.
¿Hay alguna manera de hacer que la integración continua y la TDD sean compatibles?
¿Tal vez hay una solución / práctica estándar para distinguir "nuevas pruebas" (que pueden fallar) y "pruebas de regresión" (que no deberían fallar porque solían funcionar)?
fuente
Respuestas:
Veo a dónde se dirige, pero este tipo de problemas generalmente se resuelve de otras maneras. Hay una buena razón por la cual este es un protocolo estándar. Si alguien envía un código que no se compila, todos los que actualicen su código tendrán un programa que no se compila . Eso incluye a los programadores que actualmente están trabajando en algo completamente diferente y de alguna manera se encuentran en una situación en la que necesitan esperar antes de poder compilar y probar en qué están trabajando.
El protocolo estándar es que puede confirmar los cambios incluso para un trabajo completo o incluso incompleto, siempre que se compile para que los programadores puedan actualizar su código todos los días si es necesario.
Sin embargo, todavía veo a qué te refieres. A veces desea comprometerse para simplemente guardar su código. Para esto, la mayoría de los repositorios de origen admiten ramificaciones. Esto le permite crear una rama privada, trabajar en ella sin molestar a los demás y luego fusionarse en el tronco cuando finalice el trabajo. Esto le permite comprometerse cuando lo desee sin ninguna reacción violenta asociada con la ruptura de la compilación.
Si eso no es adecuado, GIT le permite comprometerse (empujar) a repositorios en su máquina local, pero posiblemente el repositorio podría estar en cualquier lugar. Puede crear un repositorio para trabajo potencialmente parcial / incompleto y otro repositorio para trabajo terminado, y en ese repositorio puede agregar una compilación nocturna.
Nuevamente, no puedo enfatizar la importancia lo suficiente. ¡No confirmes código roto al tronco nunca! Sus contribuciones no pueden afectar el trabajo de otros programadores.
Editar
Veo que pretendías pruebas rotas, pero en mi humilde opinión, hay poca diferencia. El objetivo de una prueba es determinar si un aspecto particular de un programa pasa o falla. Si siempre falla y no hace nada, la prueba, en el uso tradicional de las pruebas unitarias, no sirve para nada. Si lo usa para realizar alguna otra métrica que no implica necesariamente una confirmación "fallida" si una de esas pruebas falla, le recomendaría encarecidamente que encuentre otra forma de hacer lo mismo.
De lo contrario, corre el riesgo de que la prueba nunca se tenga en cuenta o si hace que su compilación falle, que sus compañeros programadores ignoren las compilaciones fallidas. Es más importante que los programadores se den cuenta cuando han roto una compilación que realizar una prueba que no ofrece una visión real y que solo puede dar lugar a malas prácticas.
fuente
the build would always have failing tests
¡precisamente! ¿Pero es eso algo malo? Nuestra única métrica es "la construcción está rota o no", pero su código podría estar lleno de errores conocidos , por lo que eso realmente no significa nada, excepto que no hay regresión. En un mundo perfecto, cada problema del rastreador tendría una prueba (la reproducción es más fácil que la reparación). Entonces, la ventaja sería ver que 35 pruebas / 70% de todas las pruebas están aprobadas, que Branch-A lo mejora a 40 pruebas (80%) sin regresión, y que Branch-B tiene regresiones. Hoy solo se podría decir que Master y Branch-A están bien y Branch-B está roto.Dada una rama maestra con pruebas fallidas, ¿cómo puede estar seguro, sin comparar esa lista con las compilaciones anteriores, de que no ha introducido errores?
Simplemente rastrear el número de pruebas fallidas es insuficiente: puede corregir una prueba y romper otra. Y si está de vacaciones, no estará claro para otros que estén mirando la construcción defectuosa.
Mantenga su rama maestra limpia y verde en todo momento. Trabajar en una rama. Mantenga la sucursal debajo de CI, en un trabajo separado, y tenga pruebas fallidas del contenido de su corazón. Solo no rompas maestro.
Haga que el revisor de la sucursal solo combine su sucursal si pasa todas las pruebas. (Más fuerte: ¡haga que el revisor solo pueda fusionar su sucursal si el resultado de fusionar la sucursal en maestro pasa todas las pruebas!)
fuente
Simply tracking the number of failing tests is insufficient
esa no es la única métrica posible. Por ejemplo:Branch-A improves it to 40 tests (80% passing) with no regression
. Sin regresión significa que las pruebas aprobadas anteriormente siempre pasan. En resumen, una prueba podría fallar siempre que nunca haya pasado. Me parece que nos faltan cosas buenas al limitarnos a prohibir las pruebas fallidas en las ramas principales. (por supuesto, requeriría herramientas que funcionen de manera diferente: pruebas unitarias, CI, ...)Hay maneras de resolver sus problemas sin desechar las prácticas bien entendidas y aceptadas sobre la integración continua.
Comenzaré con el problema de cometer una 'prueba rota' que corresponde a un ticket. Una solución es crear una o más pruebas de ruptura que expongan el problema, y luego solucionar el problema , para que puedan fusionarse nuevamente en la línea de código principal. La segunda solución es tener las pruebas rotas, pero use algún tipo de indicador de ignorar para que realmente no se ejecuten y rompan la compilación. Posiblemente agregue un comentario o una anotación especial que haga muy obvio que esta es una prueba incompleta
Ticket#N
. También adjunte una nota al ticket en sí que se refiera a las pruebas creadas que esperan ser ignoradas y ejecutadas. Esto ayudaría a una persona a arreglar el boleto, pero tampoco sería una señal de alerta para alguien que se encuentre con la prueba.Y sobre su próximo problema con TDD. TDD se trata de escribir una pequeña prueba y luego escribir una pequeña porción de código para hacer que la prueba pase . Luego siga iterando hasta que tenga un pequeño módulo funcional. Siento que si escribes 4-5 pruebas, entonces te vas de vacaciones, podrías estar haciéndolo mal. Puede emparejar el programa con alguien de manera que uno de ustedes escriba la prueba y el otro el código correspondiente. Sin embargo, no debe usar el repositorio de línea de código principal para compartir este código entre ustedes dos antes de que un módulo completado esté listo para ser confirmado. Como otros sugirieron, una rama compartida resolvería sus problemas allí.
Intentar romper el mantra de integración continua puede conducir a caminos inesperados y aterradores. Por ejemplo, ¿qué significaría la cobertura de código en este tipo de entorno ? ¿Cómo no sentirían los desarrolladores que el sistema tiene muchas " ventanas rotas " ? ¿Cómo podría uno hacer un cambio, ejecutar la prueba y saber si realmente están rompiendo algo nuevo, o son solo las cosas viejas?
fuente
Creo que su problema fundamental es que está incluyendo RESULTADOS de prueba como parte de la compilación. Mientras que obviamente algunas personas están de acuerdo con usted, otras no. Romper la compilación ocurre cuando no se construye. No cuando no se construye sin errores.
Considere un proyecto importante como Windows o Linux, o incluso algo como Firefox: ¿cree que se envían sin errores? Por supuesto no. Ahora, estos proyectos no están haciendo TDD, pero eso es realmente irrelevante: TDD no cambia dos hechos fundamentales: existen errores, y lleva tiempo solucionarlos. Tiempo que un proyecto (de código abierto o no) simplemente no puede permitirse desperdiciar en errores de baja prioridad. KDE recientemente corrigió un error que tenía más de una década. ¿Cuándo fue la última vez que escuchó a alguien decir "Me alegro de que hayamos esperado una década para enviar nuestro proyecto"?
TDD, en cierto modo, probablemente hace que sea más FÁCIL enviar errores, porque tiene una mejor comprensión de cuál es la falla. Si puede definir con precisión qué causa el error, tiene una base excelente para sopesar el costo de solucionarlo.
Mi recomendación es encontrar un proyecto que no le importe algo de rojo entre el verde.
fuente
Prefiero que todas las pruebas no fallen (no rojo).
Con esta definición ligeramente diferente, también puede definir pruebas que son
Si los registra en el repositorio, su construcción continua no está rota y, por lo tanto, es válida.
fuente
Podría considerar dos "conceptos" de compilación de CI diferentes.
Una construcción de CI "futura". Esta compilación compila y ejecuta solo aquellas pruebas para las cuales no se ha escrito ningún código específicamente para hacerlas pasar. Puede haber varias razones para hacerse una prueba de este tipo:
Se pueden agregar pruebas para casos de falla específicos desde el rastreador de problemas, para el cual aún no se ha intentado ninguna solución. Es claramente útil tener una prueba codificada y en ejecución para un problema, incluso sin una solución.
Se agregaron pruebas para la nueva funcionalidad requerida que aún no se ha implementado.
A menudo es más fácil saber cómo probar una falla o característica que saber cómo implementarla o corregirla, y separar los dos pasos mediante la confirmación de la prueba al control de origen puede ser útil para garantizar que no se pierda información.
Al igual que en el CI "estándar", en el régimen de desarrollo regular, el equipo solo miraría los resultados de construcción diarios de la construcción regular.
El equipo también puede vigilar la evolución de los casos de prueba de la compilación de CI "futura", específicamente para ver si los cambios realizados en la CI regular realmente solucionan problemas de la compilación "futura", lo que puede ser una indicación de un importante problema subyacente o mejora del diseño.
Finalmente, si un miembro del equipo tiene tiempo extra en sus manos, podría echar un vistazo para solucionar uno de los problemas del "futuro", y si logran migrarlo a "regular" (mientras actualiza el estado del rastreador de problemas).
fuente
El problema no es el fracaso de las pruebas, es un indicador de regresión simple y sin contexto. Aka: como desarrollador, ¿puedo verificar un solo indicador y saber si introduje una regresión o un código de ruptura?
En el momento en que introduce el concepto de fallas "suaves" (está bien, estamos trabajando en ello / aún no implementado / estamos esperando la nueva versión / va a pasar nuevamente una vez que se solucione esta otra compilación), necesita todos los que puedan correr o mirar la prueba para conocer el estado esperado. Lo que en un equipo lo suficientemente grande va a cambiar por hora: su indicador deja de tener sentido. En un contexto más pequeño (prueba de integración privada del equipo, por ejemplo), entonces creo que es como una deuda técnica y está bien, solo necesita ser administrado.
La forma en que la mayoría de las direcciones de herramientas es 'verde / pasando' refleja cuál es el resultado esperado, no es que el código esté funcionando:
Estos vienen con sus propios problemas (¿cómo se distingue entre 'sí, sabemos que está roto, trabajando en ello' y 'el comportamiento correcto es una excepción'), pero ayudan.
fuente
Yo uso pruebas omitidas.
En el marco de prueba de unidad particular que uso, puedo generar una excepción SkipTest. La prueba no se ejecuta realmente, y su falla no interrumpirá la compilación. Sin embargo, puedo ver la cantidad de pruebas omitidas y ver si hay trabajo por hacer en esa área.
fuente