TDD y control de versiones

25

Actualmente estoy aprendiendo sobre TDD y estoy tratando de ponerlo en práctica en mis proyectos personales. También he usado el control de versiones ampliamente en muchos de estos proyectos. Estoy interesado en la interacción de estas dos herramientas en un flujo de trabajo típico, especialmente cuando se trata de la máxima para mantener pequeños compromisos. Aquí hay algunos ejemplos que vienen a la mente:

  1. Comienzo un nuevo proyecto y escribo una prueba simple para crear una clase que aún no existe. ¿Debo confirmar la prueba antes de escribir la clase aunque la prueba ni siquiera se compila? ¿O debería eliminar la cantidad mínima de código que se necesita para que la prueba se compile antes de comprometerse?

  2. Encuentro un error y escribo una prueba para recrearlo. ¿Debo confirmar la prueba fallida o implementar la corrección de errores y luego confirmar?

Estos son los dos ejemplos que vienen inmediatamente a la mente. Siéntase libre de proporcionar ejemplos adicionales en su respuesta.

Editar:

Supuse en ambos ejemplos que inmediatamente después de escribir la prueba escribiré el código para que la prueba pase. También podría surgir otra situación: trabajo en un proyecto usando TDD durante varias horas sin comprometerme. Cuando finalmente me comprometo, quiero dividir mi trabajo en pequeños trozos. (Git hace que esto sea relativamente fácil incluso si desea confirmar solo algunos de los cambios en un solo archivo).

Esto significa que mi pregunta es tanto sobre qué comprometerse como cuándo comprometerse.

Code-Guru
fuente

Respuestas:

21

¿Debo confirmar la prueba antes de escribir la clase aunque la prueba ni siquiera se compila? ¿O debería eliminar la cantidad mínima de código que se necesita para que la prueba se compile antes de comprometerse?

Por supuesto no. Debes terminar tanto el examen como la clase. Cometer algo 1 que ni siquiera compila no tiene sentido, y ciertamente hará enojar a las personas que trabajan en el mismo proyecto si lo haces con regularidad.

Encuentro un error y escribo una prueba para recrearlo. ¿Debo confirmar la prueba fallida o implementar la corrección de errores y luego confirmar?

No, no cometas una prueba fallida. La Ley de LeBlanc establece:

Más tarde es igual a nunca.

y su prueba puede fallar por mucho tiempo. Es mejor solucionar el problema tan pronto como se detecte.

Además, el estilo de desarrollo TDD dice:

El desarrollo basado en pruebas repite constantemente los pasos de agregar casos de prueba que fallan, pasarlos y refactorizar.

Si registra una prueba fallida, eso significa que no completó el ciclo.


1 Cuando dije commit, me refería a realmente commit to the trunk (para usuarios de git, empuje sus cambios, para que otros desarrolladores los reciban).

BЈовић
fuente
44
"y ciertamente hará enojar a las personas que trabajan en el mismo proyecto si" - alguien está viviendo en el mundo SVN usa GIT y no harás enojar a nadie
Mateusz
3
Creo que comprometerse está bien después de escribir una prueba, simplemente no lo presiones hasta que hayas terminado.
Matsemann
44
@radarbob ¿Esto aplica incluso para un DVCS donde hay una distinción entre comprometerse y presionar? Puedo imaginar una situación en la que realizo varias confirmaciones en mi repositorio local de git donde, en la confirmación final, la compilación no se rompe, pero en cualquiera de las confirmaciones provisionales podría ser.
Code-Guru
66
No, no cometas una prueba de fracaso. Pero uno de los puntos de TDD es precisamente hacer una prueba fallida antes de la codificación. Entonces, cometer una prueba fallida tiene sentido.
Mouviciel
44
@ Code-Guru: Para un DVCS, esas reglas deberían ser: "No confirme el código roto en una rama de la que otros se extraen regularmente". Si otros no se retiran de su repositorio local, eso puede estar en cualquier estado con el que pueda vivir.
Bart van Ingen Schenau
6

¿Debo confirmar la prueba antes de escribir la clase aunque la prueba ni siquiera se compila?

No.

¿Debo cometer la prueba reprobatoria?

No.

Estás hablando de dos paradigmas aquí:

  1. desarrollo impulsado por pruebas, que no dice nada sobre la confirmación de código. De hecho, le informa sobre cómo escribir código y cuándo ha terminado. Por lo tanto, consideraría cada 'hecho' como candidato para un compromiso.
  2. desarrollo ágil, específicamente: "comprometerse temprano y con frecuencia" (que no requiere TDD). La idea detrás de esto es tener una integración temprana con otros componentes en el sistema y así obtener retroalimentación temprana. Si se compromete en un DVCS localmente y no presiona, no tiene valor en ese sentido. Los compromisos locales solo ayudan a los desarrolladores a estructurar su trabajo.

Mi recomendación es: siga el círculo de TDD hasta que se compile su código, sus pruebas sean verdes y tenga algo para contribuir al sistema. Por lo tanto, debe cortar sus funciones verticalmente, por ejemplo, para una nueva máscara de interfaz de usuario, no cree todo el formulario y se comprometa sin la lógica empresarial, sino que implemente un aspecto pequeño pero en la interfaz así como en la lógica empresarial y en la capa de persistencia .

Para una corrección de error grande, confirme después de cada mejora (por ejemplo, refactorización), incluso si el error aún no se ha solucionado. Sin embargo, las pruebas deben ser verdes y el código debe compilarse.

Andy
fuente
5

Ciertamente, comienza con el uso de un control de fuente saludable como git.

Luego puede trabajar de la manera que desee y comprometerse en cada esquina: cualquier paso o subpaso es un juego justo.

Luego, antes de empujar las cosas, aplastas todo el trabajo en una sola confirmación. O una pareja, en puntos donde todo es verde y la composición tiene sentido. Y empujar esos compromisos sensatos. Para el caso múltiple, conviértalo en una rama que combine con --no-ff.

El control de la fuente no es un sistema de seguimiento del trabajo ni un historiador. Los commits presentarán un delta coherente y sensible, mientras que el estado de pago estará compilando al menos. Los intermedios pueden conservarse durante un tiempo para fines de revisión, pero una vez que todo se considera correcto, un solo compromiso por función es justo.

Balog Pal
fuente
5

Según tengo entendido del mundo, uno se compromete a marcar un punto al que puede ser conveniente volver. El punto a que falla una prueba (pero se compila) es definitivamente uno de esos puntos. Si tuviera que desviarme en la dirección equivocada tratando de hacer un pase de prueba, me gustaría poder revertir el código al punto de partida e intentarlo nuevamente; No puedo hacer esto si no me he comprometido.

Scroog1
fuente
Estoy de acuerdo contigo. Prefiero usar una rama diferente para seguir la regla "no rompa la compilación" y combine los cambios en el tronco solo cuando pase la prueba.
Fil
5

¿Debo confirmar la prueba antes de escribir la clase aunque la prueba ni siquiera se compila?

Con un SCM bifurcado (vi que usaba Git), debe confirmar cada vez que desee un punto de respaldo ("Arruine algo; restableceré el directorio de trabajo al último punto de respaldo") o cuando tenga una versión estable. Cuando tiene una versión estable (todas las pruebas pasan), también debe considerar fusionar la rama de la característica actual en su rama de desarrollo principal.

¿O debería eliminar la cantidad mínima de código que se necesita para que la prueba se compile antes de comprometerse?

Depende de usted (git le brinda la flexibilidad de comprometerse cuando lo desee sin afectar a otros miembros de su equipo, o su capacidad para trabajar en diferentes funciones). Solo asegúrese de no tener varias funciones incompletas (que no funcionen) en la misma rama al mismo tiempo (luego se bloquearán entre sí).

Encuentro un error y escribo una prueba para recrearlo. ¿Debo confirmar la prueba fallida o implementar la corrección de errores y luego confirmar?

Por lo general, hago dos confirmaciones para eso, a menos que el código de prueba sea realmente pequeño / trivial para escribir.

Estos son los dos ejemplos que vienen inmediatamente a la mente. Siéntase libre de proporcionar ejemplos adicionales en su respuesta.

Editar:

Supuse en ambos ejemplos que inmediatamente después de escribir la prueba escribiré el código para que la prueba pase.

Esa podría ser una suposición equivocada. Si trabaja solo (proyecto personal), nada le impide hacerlo siempre. En uno de mis proyectos más exitosos (con respecto a mantener una alta calidad de código y TDD durante el desarrollo del proyecto) definimos pruebas a veces semanas antes de implementarlas (es decir, "la prueba" test_FOO_with_null_first_parameter "ahora se define como una función vacía y comprometerlo así). Luego tomaríamos un sprint (o medio sprint) a veces un mes más tarde, por aumentar la cobertura de prueba para el módulo. Ya que teníamos las pruebas ya declaradas, era fácil de estimar.

También podría surgir otra situación: trabajo en un proyecto usando TDD durante varias horas sin comprometerme. Cuando finalmente me comprometo, quiero dividir mi trabajo en pequeños trozos. (Git hace que esto sea relativamente fácil, incluso si desea confirmar solo algunos de los cambios en un solo archivo). Esto significa que mi pregunta es tanto sobre qué comprometer como cuándo comprometer.

Yo diría que definitivamente se comprometan a crear puntos de copia de seguridad . Esto funciona muy bien para las pruebas exploratorias ("Solo agregaré algunas impresiones en toda la base del código, ejecutarlas y git reset --hardeliminarlas cuando termine) y para la creación de prototipos.

utnapistim
fuente
2
Tenga cuidado al recomendar git reset --hard. Es uno de los pocos comandos en git que te hará perder trabajo.
gnash117
2

En mi flujo de trabajo, siempre que sea posible hago un trabajo incierto en una rama de control de fuente personal. Entonces puedo intentar, fallar, intentar nuevamente si es necesario hasta que funcione, y solo comprometerme con el proyecto más grande cuando tenga un código de trabajo real.

Desde la perspectiva de TDD, la pregunta "¿se registra primero en la prueba?" depende completamente del código en el que está trabajando. Si se trata de un código nuevo, no registra nada hasta que tenga algo que valga la pena. Pero si se trata de un error que se encuentra en el código ya compilado o enviado, vale la pena registrarse en una prueba para reproducir el error, POR SI MISMO. Especialmente si es el final de un día de trabajo, y saldrá de la oficina antes de arreglarlo el código.

(Por supuesto, si su taller tiene un proceso de construcción automatizado que muere si falla alguna de las pruebas unitarias, es posible que no desee verificar una prueba fallida hasta que solucione el error. Pero esa parece una forma extraña de trabajar, ya que "encontrar y los errores en los documentos "y" errores corregidos "pueden ser realizados por dos equipos completamente diferentes).

DougM
fuente