Metodología: escritura de pruebas unitarias para otro desarrollador

28

Estaba pensando en el desarrollo de software y en escribir pruebas unitarias. Tengo la siguiente idea:

Supongamos que tenemos pares de desarrolladores. Cada par es responsable de una parte del código. Uno del par implementa una característica (escribir código) y el segundo escribe una unidad de pruebas para ello. Las pruebas se escriben después del código. En mi idea, se ayudan mutuamente, pero funcionan bastante por separado. Idealmente, trabajarían en dos características de tamaño similar y luego cambiarían por la preparación de la prueba.

Creo que esta idea tiene algunas ventajas:

  • las pruebas son escritas por alguien que puede ver más sobre la implementación,
  • el trabajo debe hacerse un poco más rápido que la programación en pareja (dos funciones al mismo tiempo),
  • tanto las pruebas como el código tienen una persona responsable de ello,
  • el código es probado por al menos dos personas y
  • quizás buscar errores en el código escrito por la persona que está probando su código le daría una motivación especial para escribir un código mejor y evitar recortes.

Quizás también sea buena idea agregar otro desarrollador para la revisión del código entre el desarrollo del código y las pruebas.

¿Cuáles son las desventajas de esta idea? ¿Ya se describe como una metodología desconocida para mí y se utiliza en el desarrollo de software?

PD. No soy un administrador de proyectos profesional, pero sé algo sobre los procesos de desarrollo de proyectos y conozco las pocas metodologías más populares, pero esta idea no me suena familiar.

franiis
fuente
17
Solo está describiendo el control de calidad descendente a nivel de unidad. Si tienes pares de personas trabajando en algo, ¿has probado la programación de pares reales con TDD?
jonrsharpe
9
Esto funcionaría mejor si el escritor de pruebas realizara primero las pruebas (escribir código esqueleto) y el otro implementara la funcionalidad. El primero tendría el control del diseño y el otro haría el trabajo pesado. Eso podría funcionar bien si el primero sabe lo que está haciendo y al segundo no le importa seguir su ejemplo todo el tiempo. No sé sobre un nombre para esta forma de cooperación. Yo diría ... ¡reclámalo! Comience a llamar a este desarrollo de Franiis.
Martin Maat
14
Esa crítica no tiene sentido, y su sugerencia no resuelve ese problema.
jonrsharpe
55
@franiis He visto colegas escribir assert truecomo pruebas y llamarlo un día porque cada prueba estaba pasando. Faltaba un paso importante: las pruebas deberían fallar primero, y deberían aprobarse cambiando el código, no las pruebas.
Eric Duminil
66
@franiis TDD se basa en la iteración. Escribir prueba de reprobación. Escriba el código que hace que la prueba sea verde. Refactorizador Escribe una prueba reprobatoria. Escriba el código que hace que la prueba sea verde. Refactorizador Parece que te falta la parte "repite hasta que tengas pruebas que cubran todos tus requisitos". Pero el mayor problema que parece tener es que las "pruebas" se consideran algo que debe tener porque alguien lo dijo, en lugar de que las pruebas sean una herramienta útil para los desarrolladores . Si no puede hacer que las personas se preocupen por la calidad (y la corrección) de su código, ese es su problema, y ​​ahí es donde debe comenzar.
Luaan

Respuestas:

30

El enfoque general de usar pares para dividir el esfuerzo de escribir código de producción y escribir sus pruebas unitarias asociadas no es infrecuente. Incluso me he emparejado personalmente de esta manera antes con un éxito decente. Sin embargo, una línea estricta entre la persona que escribe el código de producción y la persona que escribe el código de prueba puede no necesariamente arrojar resultados.

Cuando utilicé un enfoque similar, la pareja comienza hablando y obteniendo una comprensión compartida del problema. Si está utilizando TDD, entonces puede comenzar con algunas pruebas básicas primero. Si no está utilizando TDD, tal vez comenzará con la definición del método. A partir de aquí, ambos miembros de la pareja trabajan tanto en el código de producción como en el código de prueba, y una persona se enfoca en cada aspecto, pero habla sobre formas de mejorar el código de producción y el código de prueba detrás de él.

No veo la ventaja de dar a cada par dos características. Lo que terminaría es algo que se asemeja a TDD para algunas características y algo que no lo es para otras características. Pierdes el foco. No obtiene los beneficios de la revisión por pares en tiempo real. No obtienes ninguno de los principales beneficios del emparejamiento.

La práctica de la programación de pares no se trata de velocidad, sino de calidad. Por lo tanto, tratar de usar una técnica modificada impulsada por ir más rápido va en contra de la naturaleza. Al crear un software de mayor calidad a través de la revisión de código paralelo y el desarrollo de pruebas, terminará ahorrando tiempo aguas abajo, ya que hay al menos dos personas con conocimiento de cada cambio y está eliminando (o reduciendo) los ciclos de espera para la revisión y prueba por pares.

Thomas Owens
fuente
Gracias, mi idea supone que ambas características se desarrollan de la misma manera (pero los desarrolladores intercambian roles), solo para aclarar, no para defender el sentido de ese concepto. Me gusta su respuesta y su enfoque en la velocidad frente a la calidad.
Franiis
En mi experiencia, los costos de retrabajo superan los beneficios de este enfoque. Prefiero que un par intercambie estas tareas usando 'ping-pong' u otro método.
neontapir
3
La práctica de la programación de pares no se trata de velocidad, sino de calidad. Pair TDD se trata de calidad, que brinda velocidad de finalización, lo que conlleva menores costos de desarrollo. Es solo que nuestra industria está aprendiendo lo que los albañiles han conocido por los millenials: su muro se construirá mejor en menos tiempo, con menos esfuerzo y menos costo si pierde algo de tiempo configurando primero una línea de cuerda y una regla de albañil, luego coloque sus ladrillos, que si colocas tu ladrillo e intentas ajustarte luego con el nivel de burbuja y el mazo. Y obtener ayuda con las cosas.
Laurent LA RIZZA
@LaurentLARIZZA Eso parece correcto. Supongo que una mejor manera de decirlo sería "La práctica de la programación de pares no se trata de velocidad en el presente, sino de calidad y velocidad en el futuro". Definitivamente, es una práctica progresista encontrar problemas antes, mejorar la solidez del trabajo y compartir conocimientos para derribar los silos. Todos estos tienen un costo ahora que a menudo pagará recompensas en el futuro.
Thomas Owens
@ThomasOwens: Bueno, el costo de la calidad solo se percibe, no es real. Una vez que pasa la prueba (y ha arreglado su código), el escenario descrito por su prueba está hecho y asegurado, y obtiene la confianza de que funciona como se esperaba. Ya está hecho, y puedes seguir adelante. Si continúa sin la certeza de que el código funciona, acaba de aceptar una deuda que tendrá que realizar los controles más adelante. Costo de las deudas, no la ausencia de deudas. Quiero decir, el "futuro" del que hablas es tan pronto como pase tu primera prueba.
Laurent LA RIZZA
37

El principal problema con su idea es que no puede simplemente escribir pruebas para cualquier código. El código tiene que ser comprobable.

Es decir, debe poder inyectar simulacros, separar el bit que desea probar, acceder al estado que se cambia y necesita confirmación, etc.

A menos que tenga suerte o escriba la prueba primero, es probable que escribir la prueba signifique reescribir un poco el código. Lo cual, si usted no es la persona que escribe el código en primer lugar, significará demora, reuniones, refactorización, etc.

Ewan
fuente
Gracias. pero la crítica común de TDD es que el código a veces / a menudo se escribe para hacer que las pruebas sean "verdes", no para ser bueno. Si las pruebas no prueban algún aspecto del código, entonces podría omitirse en el código. Escribir la prueba más tarde podría ayudar a esto (acepto que se pueden requerir algunos cambios después de escribir el código, pero los desarrolladores deberían aprender a escribir más código comprobable en el futuro).
franiis
1
@frani, claro, el problema principal no es que escribas las pruebas después, es la combinación de hacer eso y no ser la misma persona que escribió el código.
Ewan
pero si se usa, por ejemplo, la programación de pares consumiría menos tiempo. Si dos desarrolladores trabajan en un terminal, no pueden trabajar simultáneamente en dos funciones, y mi idea debería permitir esto (incluso en un alcance limitado). Las reuniones para un micro equipo de 2 personas no deberían ser una carga real.
franiis
25
@franiis: "Si las pruebas no prueban algún aspecto del código, entonces podría omitirse en el código". - Ese es el punto. Las pruebas son una codificación de los requisitos en forma de ejemplos ejecutables. Si no hay prueba para ello, entonces no hay ningún requisito para ello, y no debería haber código para ello .
Jörg W Mittag
3
El otro lado de lo que dijo @ JörgWMittag sería: si sus pruebas "no prueban algo importante del código", entonces necesita corregir sus pruebas. Esto será tan cierto en su sistema como lo es en TDD tradicional.
bta
15

El problema principal que veo aquí, a nivel de unidad, cuando escribo código, quiero compilarlo, ejecutarlo y eliminar los errores más obvios de inmediato, incluso cuando el código está incompleto y sé que la unidad, característica o función es solo parcialmente implementado. Y para ejecutar el código de una unidad, necesito algún programa que llame a la implementación, generalmente una prueba unitaria o al menos una prueba unitaria parcial. Esto no es necesariamente "estilo TDD por el libro", tal prueba se puede escribir después o antes del código bajo prueba.

Cuando una versión de mi unidad es "completa" y está libre de todos los errores que puedo encontrar por mí mismo, entonces tiene sentido entregarla a una segunda persona y dejar que escriba pruebas de unidad adicionales o revise mi código . Pero para mí no tiene sentido entregarlo tan pronto como el compilador no muestre advertencias, eso definitivamente es demasiado temprano en caso de que sepa que tuve que explicar al probador en detalle las cosas que no funcionan "todavía", o funcionarán diferente en dos horas ya que todavía estoy trabajando en ese código. La sobrecarga de comunicación necesaria para esto en ese nivel de detalle en mi humilde opinión no estaría equilibrada por los beneficios.

Entonces, sí, tener un segundo desarrollador escribiendo pruebas unitarias adicionales tiene sentido, pero no para escribir las pruebas unitarias exclusivamente .

Doc Brown
fuente
7

Parece que existe la posibilidad de que ocurra cualquiera de las siguientes situaciones, todas las cuales son indeseables:

Confusión

Como Ewan describió, el CUT podría necesitar un cambio para que sea comprobable. La razón del cambio no siempre es obvia para el desarrollador (y puede causar desacuerdos), razón por la cual las pruebas se escriben primero.

Contención

El desarrollador A puede haber completado su código y querer probarlo. El desarrollador B también puede estar en desarrollo y, por lo tanto, puede ser reticente a estacionar su código para asistir a las pruebas unitarias.

Cambio de contexto

Incluso si el desarrollador B está dispuesto a archivar su desarrollo para probar el código escrito por el desarrollador A , el cambio en la actividad tiene un costo.


Durante décadas se ha aceptado que duplicar el poder humano no reduce a la mitad el tiempo de desarrollo. Teniendo en cuenta los factores que he esbozado anteriormente, es difícil ver cómo este arreglo mejoraría las cosas.

Robbie Dee
fuente
4

Cuando se usa junto con la programación de pares y TDD, esto se llama Patrón Ping Pong :

  • A escribe una nueva prueba y ve que falla.
  • B implementa el código necesario para pasar la prueba.
  • B escribe la siguiente prueba y ve que falla.
  • A implementa el código necesario para pasar la prueba.

Y así. La refactorización se realiza cada vez que surge la necesidad de quien conduce.

Pero parece proponer que ambos programadores codifiquen con computadoras diferentes. Hacerlo por separado requeriría tener una especificación de nivel muy bajo. Esto va en contra de las metodologías ágiles. Cada cambio necesitaría ser coordinado. En TDD está haciendo el diseño de bajo nivel sobre la marcha y no es un problema. Supongo que su enfoque requeriría tener algún tipo de esqueletos ya codificados.

De todos modos: puedes aprender mucho probando nuevas formas de hacer las cosas, incluso si no son 100% eficientes. Puedes probarlo y compartir tu experiencia de la vida real

Borjab
fuente
3

Llego tarde a esta fiesta, pero creo que tengo algo que agregar.

¿Ya se describe como una metodología desconocida para mí y se utiliza en el desarrollo de software?

Estás describiendo las pruebas entre pares .

Supongamos que tenemos pares de desarrolladores.

Ah, buena programación de parejas .

Cada par es responsable de una parte del código. Uno del par implementa una característica (escribir código) y el segundo escribe una unidad de pruebas para ello. Las pruebas se escriben después del código. En mi idea, se ayudan mutuamente, pero funcionan bastante por separado.

Eso no es programación de pares.

Idealmente, trabajarían en dos características de tamaño similar y luego cambiarían por la preparación de la prueba.

Eso definitivamente es prueba de pares. Aquí hay un documento de ACM al respecto . He hecho esto He trabajado donde era una parte formal de la proceso de revisión por pares . Es útil, pero ciertamente no está destinado a ser la primera línea de prueba, y ciertamente no es la clásica programación de pares.

Otro nombre para esto es Whitebox Testing . Aunque esa definición no se refiere a quién está haciendo las pruebas tanto como al hecho de que el probador puede ver el funcionamiento interno de la cosa que están probando, a diferencia de las pruebas de Black Box donde solo ven lo que entra y lo que sale La caja negra es típicamente lo que hace el control de calidad.

La primera línea de prueba descansa firmemente en las manos del codificador. Si no es así, me estás pidiendo que no pruebe mi código yo mismo, lo que me niego rotundamente a hacer. He estado probando mi código desde que tenía 10 años. Es posible que no haya probado con pruebas unitarias elegantes en ese entonces, pero mi código fue probado. Fue probado cada vez que lo ejecuté.

Lo que espero de un probador de pares es pruebas que se agregan a mis pruebas. Pruebas que aclaran abundantemente los problemas que el compañero encontró con el código cuando lo revisaron. Al expresar estos problemas con una prueba automatizada, es mucho más fácil entender lo que significan. De hecho, he tenido conversaciones técnicas con compañeros que simplemente no podían ver el punto que estaba haciendo y luego me di cuenta de que la mejor manera de mostrarles el problema era escribir una prueba unitaria. Eso es prueba de pares.

Ahora, si quieres darme pruebas escritas antes de que escriba mi código bien. Nada como un documento de requisitos tan formal que se compila.

naranja confitada
fuente
Gracias por la respuesta y por señalarme a las Pruebas entre pares (lo leeré).
Franiis
1

He realizado DDT (pruebas impulsadas por el desarrollo, también conocidas como pruebas después del código), programación de pares y TDD rojo-verde-refactorizador durante varios años cada uno. Para responder a sus afirmaciones punto por punto:

las pruebas son escritas por alguien que puede ver más sobre la implementación

La persona que escribe las pruebas necesita conocer la implementación de la forma más íntima posible, para escribir pruebas con una buena cobertura sin excesivas pruebas. El ejemplo clásico de esto es probar con tres entradas cuando dos probarían lo que está tratando de probar. Si bien pueden lograr una familiaridad superficial con el código al leerlo, no podrán entender exactamente por lo que el desarrollador original pasó para llegar al estado actual. Entonces tendrán una comprensión menos que óptima del código.

el trabajo debe hacerse un poco más rápido que la programación en pareja (dos funciones al mismo tiempo)

No entiendo por qué dices eso. Mientras alguien escribe pruebas, no está trabajando en nuevas funciones. No puedes doblar mágicamente la capacidad de trabajo de alguien dándole dos tipos diferentes de trabajo. En mi experiencia, escribir pruebas es generalmente más difícil que escribir código de producción, por lo que definitivamente no podría trabajar de manera productiva y responsable en las pruebas de algún código mientras escribe otra función.

tanto las pruebas como el código tienen una persona responsable

Primero, las pruebas son código. Para el negocio, el código de prueba es casi tan importante como el código de producción, porque permite que el negocio cambie el software sin temor. En segundo lugar, esto no es diferente de una persona que escribe las pruebas y el código de producción, o incluso un par que escribe ambos.

el código es probado por al menos dos personas

No, solo lo prueba la persona que escribe el examen. A menos que quiera usar aún más tiempo en las pruebas, en cuyo caso, ¿por qué detenerse a las dos?

quizás buscar errores en el código escrito por la persona que está probando su código le daría una motivación especial para escribir un código mejor y evitar recortes.

Los desarrolladores (incluso los superiores) tienen ideas muy diferentes sobre lo que constituye un código "bueno". El corte de esquina de una persona es la forma perfectamente válida de otra de llegar al código de trabajo lo antes posible. Esta es una receta para culpar y para jugar con el sistema.

TDD rojo-verde-refactor (en realidad escribe una sola prueba antes de escribir el código de producción, ejecutarlo, verlo fallar, modificar solo el código de producción , ejecutar la prueba nuevamente, ver que tiene éxito y luego refactorizar, y no omitir ni intercambiar ninguno de estos pasos) y las revisiones de código funcionan.

l0b0
fuente
Sería más rápido (presumiblemente) porque no hay dos personas haciendo el "mismo trabajo": cada una de ellas está haciendo lo suyo y luego intercambian a mitad de camino.
Jacob Raihle
@JacobRaihle Pairing no son dos personas que se desarrollan juntas sin comunicación. Serían dos personas haciendo el mismo trabajo. El emparejamiento es realmente eficiente porque dos personas están colaborando en un trabajo. En mi experiencia, el desarrollo es casi tan rápido como para los programadores individuales (es decir, las parejas realizan el trabajo dos veces más rápido), el software resultante es de mucha mayor calidad y el conocimiento se ha compartido.
l0b0
Estoy tratando de explicar la lógica detrás de "el trabajo debe hacerse un poco más rápido", lo que pareció confundirlo. El emparejamiento suele ser más lento en mi experiencia, aunque sigo pensando que vale la pena (preferible tanto para el trabajo individual como para la entrega de pruebas de OP). Si es más rápido para ti, mucho mejor.
Jacob Raihle
1

Creo que esta idea tiene algunas ventajas:

Vamos a recorrerlos uno por uno.

las pruebas son escritas por alguien que puede ver más sobre la implementación,

Entonces, quiere decir que el primer desarrollador ha pasado tiempo escribiendo alguna implementación, que no está seguro de que funcione. Luego, otro desarrollador viene y escribe pruebas, basando su razonamiento en el código que nadie sabe si es correcto, y con la esperanza de que traiga una ventaja táctica en comparación con escribir pruebas solo con respecto a lo que se supone que debe hacer el código. Si la implementación es incorrecta, mi opinión será que no aporta ayuda para escribir pruebas.

el trabajo debe hacerse un poco más rápido que la programación en pareja (dos funciones al mismo tiempo)

Una vez que ambos desarrolladores han terminado su desarrollo inicial, nadie sabe si alguno de sus códigos es correcto. Esto aún no se ha verificado, nadie puede marcar a nadie como hecho, y nadie puede predecir cuándo se hará. Compare esto con TDD: primero escribe la prueba, luego la prueba falla, luego pasa con el código. Ese es el código que admite más y más escenarios. Eso es movimiento hacia adelante.

Si los hace progresar en paralelo, el código que podría reutilizarse en ambas características se escribirá dos veces y costará dos veces más.

tanto las pruebas como el código tienen una persona responsable de ello,

Examine la propiedad del código colectivo, como lo propone XP. Tendrás aún más personas responsables del código. Si su objetivo es compartir el conocimiento entre los desarrolladores, ¿por qué intenta segregarlos?

el código es probado por al menos dos personas

Con par TDD también. Al emparejar, ambas personas deben aceptar que el código escrito es adecuado o no escribirlo. Si eso resulta en una pelea, algunas personas en el equipo tienen un problema de ego fuera de lugar.

quizás buscar errores en el código escrito por la persona que está probando su código le daría una motivación especial para escribir un código mejor y evitar recortes.

La búsqueda de errores implica que, en algún momento, usted toleró que ingresaran. Si ingresaron, pasarían desapercibidos. Negarse a escribir pruebas primero es dar licencia a los errores para ingresar.

La esquina cortante puede ser involuntaria. Para eso es la programación de pares. Se debe instruir a cada miembro de la pareja con el deber de no dejar que el otro corte esquinas, porque bueno, todos hacemos eso. Eso requiere dejar su orgullo en el armario y recuperarlo cuando salga de la oficina. Si espera que su gente sea infaliblemente rigurosa, no está considerando la situación común y se prepara para el fracaso.

XP dice explícitamente que todas las prácticas XP están hechas para reforzarse mutuamente cubriendo los defectos del otro. No debe escuchar las críticas a ninguna práctica de XP separada de las demás. Ninguna práctica es perfecta, TDD no es perfecto, la programación de pares no es perfecta, la propiedad del código colectivo no es perfecta, pero todos se cubren entre sí.

Laurent LA RIZZA
fuente