¿Por qué no escribe todas las pruebas a la vez cuando se realiza TDD?

52

El ciclo Rojo - Verde - Refactor para TDD está bien establecido y aceptado. Escribimos una prueba de unidad fallida y la hacemos pasar tan simple como sea posible. ¿Cuáles son los beneficios de este enfoque sobre la escritura de muchas pruebas unitarias fallidas para una clase y hacer que todas pasen de una vez?

El conjunto de pruebas aún lo protege contra la escritura de código incorrecto o cometer errores en la etapa de refactorización, ¿cuál es el daño? A veces es más fácil escribir todas las pruebas para una clase (o módulo) primero como una forma de "volcado de cerebro" para escribir rápidamente todo el comportamiento esperado de una sola vez.

    
pregunta RichK 02.04.2012 - 15:32

16 respuestas

45

El diseño basado en pruebas consiste en hacer que su API sea correcta, no el código.

La ventaja de escribir primero las pruebas con fallas más simples es que obtiene su API (que esencialmente es lo que está diseñando sobre la marcha) lo más simple posible. Al frente.

Todos los usos futuros (que son las siguientes pruebas que escriba) irán desde el diseño simple inicial, en lugar de un diseño subóptimo que haga frente a casos más complejos.

    
respondido por el user1249 02.04.2012 - 14:12
72

Cuando escribe una prueba, se concentra en una .
Con muchas pruebas, extiendes tu atención en muchas tareas, por lo que no es una buena idea.

    
respondido por el Abyx 02.04.2012 - 12:29
25

Una de las dificultades al escribir pruebas unitarias es que está escribiendo un código, y eso en sí mismo puede ser propenso a errores. También existe la posibilidad de que necesite terminar cambiando sus pruebas más adelante como resultado de un esfuerzo de refactorización a medida que escribe su código de implementación. Con TDD, esto significa que posiblemente podría terminar un poco demasiado impresionado con sus pruebas y encontrar que necesita volver a escribir una gran cantidad de código de prueba esencialmente "no probado" a medida que su implementación madura en el transcurso del proyecto. Una forma de evitar este tipo de problema es simplemente concentrarse en hacer una sola cosa a la vez. Esto garantiza que minimice el impacto de cualquier cambio en sus pruebas.

Por supuesto, esto dependerá en gran medida de cómo escriba su código de prueba. ¿Está escribiendo una prueba de unidad para cada método individual, o está escribiendo pruebas que se centran en características / requisitos / comportamientos? Otro enfoque podría ser utilizar un enfoque basado en el comportamiento con un marco adecuado, y centrarse en escribir pruebas como si fueran especificaciones. Esto significaría adoptar el método BDD o adaptar la prueba BDD si desea mantener el TDD de manera más formal. Alternativamente, puede seguir el paradigma de TDD, pero al mismo tiempo modificar la forma en que escribe las pruebas para que, en lugar de centrarse completamente en los métodos de prueba individualmente, pruebe los comportamientos de manera más general como un medio para satisfacer las características específicas de los requisitos que está implementando.

Independientemente del enfoque específico que adopte, en todos los casos que he descrito anteriormente, está utilizando un enfoque de primera prueba, por lo que aunque puede ser tentador simplemente descargar su cerebro en un conjunto de pruebas encantador, también desea Combatir la tentación de hacer más de lo absolutamente necesario. Cada vez que estoy a punto de comenzar un nuevo conjunto de pruebas, comienzo a repetirme YAGNI a mí mismo, e incluso a veces lo incluyo en un comentario en mi código para recordarme que me centre en lo que es inmediatamente importante y que solo haga lo mínimo requerido para satisfacer Los requisitos de la característica que estoy a punto de implementar. Apegarse a Red-Green-Refactor ayuda a garantizar que hará esto.

    
respondido por el S.Robins 26.04.2012 - 02:05
16

Creo que al hacer esto, se pierde el proceso de TDD. Al escribir todas sus pruebas al comienzo, realmente no está pasando por el proceso de desarrollo utilizando TDD. Simplemente estás adivinando por adelantado qué pruebas necesitarás. Este será un conjunto de pruebas muy diferente de las que terminará escribiendo si las realiza una a la vez a medida que desarrolla su código. (A menos que su programa sea trivial por naturaleza).

    
respondido por el ZweiBlumen 02.04.2012 - 14:33
10

La idea detrás de TDD es iteraciones rápidas.

Si tienes una gran cantidad de pruebas que deben escribirse antes de escribir tu código, es difícil refactorizar iterativamente tu código.

Sin una refactorización fácil del código, perderá muchos de los beneficios de TDD.

    
respondido por el linkerro 29.11.2013 - 14:56
9

Yo "escribo" todas las pruebas en las que puedo pensar por adelantado mientras "hago una lluvia de ideas", sin embargo, escribo cada prueba como un solo comentario que describe la prueba.

Luego convierto una prueba a código y hago el trabajo para que compile y pase . A menudo decido que no necesito todas las pruebas que pensé que hice, o necesito pruebas diferentes, esta información solo proviene de escribir el código para hacer que se aprueben las pruebas.

El problema es que no puedes escribir una prueba en código hasta que hayas creado el método y las clases que prueba, de lo contrario, obtendrás muchos errores de compilación que te ayudarán a trabajar en una sola prueba a la vez.

Ahora, si está utilizando un sistema como flujo de especificaciones cuando las pruebas están escritas en “inglés”, es posible que desee que los clientes acepten un conjunto de pruebas mientras tienen su tiempo, en lugar de solo crear una sola prueba.

    
respondido por el Ian 02.04.2012 - 13:50
5

En mi (limitada) experiencia con TDD, puedo decirte que cada vez que rompí la disciplina de escribir una prueba a la vez, las cosas han ido mal. Es una trampa fácil para caer. "Oh, ese método es trivial", piensas para ti mismo, "así que simplemente eliminaré estas otras dos pruebas relacionadas y seguiré avanzando". ¿Bien adivina que? Nada es tan trivial como parece. Cada vez que caí en esta trampa, terminé de depurar algo que pensé que pensé era fácil, pero resultó que tenía casos extraños en las esquinas. Y desde que escribí varias pruebas a la vez, fue mucho trabajo rastrear dónde estaba el error.

Si necesita un volcado de información, tiene muchas opciones:

  • pizarra
  • Historias de usuario
  • Comentarios
  • Buena pluma y papel

Observe que en ninguna parte de esta lista está el compilador. :-)

    
respondido por el Kristo 02.04.2012 - 15:43
5

Está asumiendo que sabe cómo se verá su código antes de escribirlo. TDD / BDD es tanto un proceso de diseño / descubrimiento como un proceso de control de calidad. Para una característica dada, escribe la prueba más simple que verificará que la característica está satisfecha (a veces esto puede requerir varios debido a la complejidad de una característica). La primera prueba que escribes se carga con suposiciones de cómo se verá el código de trabajo. Si escribe todo el conjunto de pruebas antes de escribir la primera línea de código para admitirlo, está haciendo una letanía de suposiciones no verificadas. En su lugar, escriba un supuesto y verifíquelo. Luego escribe el siguiente. En el proceso de verificar la siguiente suposición, es posible que simplemente rompa una suposición anterior, por lo que debe retroceder y cambiar la primera suposición para que coincida con la realidad o cambiar la realidad para que la primera suposición siga siendo válida.

Piensa en cada prueba de unidad que escribes como una teoría en un cuaderno científico. A medida que rellena el cuaderno, demuestra sus teorías y forma otras nuevas. A veces, probar que una nueva teoría refuta una teoría anterior, por lo que hay que arreglarla. Es más fácil probar una teoría a la vez en lugar de tratar de probar, por ejemplo, 20 a la vez.

    
respondido por el Michael Brown 02.04.2012 - 15:51
4

TDD es un enfoque altamente iterativo, que (en mi experiencia) se ajusta mejor a las formas de desarrollo del mundo real. Por lo general, mi implementación toma forma gradualmente durante este proceso, y cada paso puede traer más preguntas, ideas e ideas para las pruebas. Esto es ideal para mantener mi mente enfocada en la tarea real, y es muy eficiente porque solo necesito mantener un número limitado de cosas en la memoria a corto plazo en cualquier momento. Esto a su vez reduce la posibilidad de errores.

Su idea es básicamente un enfoque Big Test Up Front, que IMHO es más difícil de manejar y puede volverse más inútil. ¿Qué pasa si se da cuenta a mitad de su trabajo que su enfoque no es bueno, que su API es defectuosa y que necesita comenzar de nuevo, o usar una biblioteca de terceros? Luego, gran parte del trabajo que se pone por escrito en sus exámenes por adelantado se convierte en un esfuerzo inútil.

Dicho esto, si esto funciona para ti, está bien. Puedo imaginar que si trabaja desde una especificación técnica fija y detallada, en un dominio con una experiencia íntima y / o en una tarea bastante pequeña, es posible que tenga la mayoría o todos los casos de prueba necesarios y su implementación clara. el comienzo. Entonces podría tener sentido comenzar escribiendo todas las pruebas a la vez. Si su experiencia es que esto lo hace más productivo a largo plazo, no debe preocuparse demasiado por los libros de reglas :-)

    
respondido por el Péter Török 02.04.2012 - 12:36
4

Más allá de solo pensar en una cosa, un paradigma de TDD es escribir el menor código posible para pasar la prueba. Cuando escribe una prueba a la vez, es mucho más fácil ver la ruta para escribir solo el código suficiente para que la prueba pase. Con un conjunto completo de pruebas para aprobar, no se obtiene el código en pasos pequeños, sino que se debe dar un gran salto para que todos se aprueben de una sola vez.

Ahora, si no se limita a escribir el código para hacer que todos pasen "de una vez", sino que simplemente escriba el código suficiente para pasar una prueba a la vez, es posible que aún funcione. Sin embargo, deberías tener más disciplina para no solo seguir adelante y escribir más código del que necesitas. Una vez que empiezas por ese camino, te dejas abierto para escribir más código del que describen las pruebas, que puede ser no probado , al menos en el sentido de que no está dirigido por una prueba y quizás en el Sentir que no es necesario (o ejercitado) por cualquier prueba.

Bajar lo que debería hacer el método, como comentarios, historias, una especificación funcional, etc., es perfectamente aceptable. Sin embargo, esperaría traducirlas en pruebas una por una.

La otra cosa que puede pasar por alto al escribir las pruebas de una sola vez es el proceso de pensamiento mediante el cual pasar una prueba puede hacer que piense en otros casos de prueba. Sin un banco de pruebas existentes, debe pensar en el siguiente caso de prueba en el contexto de la última prueba que pasa. Como dije, tener una buena idea de lo que se supone que debe hacer el método es muy bueno, pero muchas veces me he encontrado con nuevas posibilidades que no había considerado a priori, pero que solo ocurrían en el proceso de escribir el pruebas Existe el peligro de que pueda pasarlo por alto a menos que adquiera el hábito de pensar qué nuevas pruebas puedo escribir que no tengo.

    
respondido por el tvanfosson 02.04.2012 - 15:08
3

He trabajado en un proyecto en el que los desarrolladores que escribieron las pruebas (que fallaron) fueron diferentes de los desarrolladores que implementaron el código necesario para hacerlos pasar y lo encontré realmente efectivo.

En ese caso, solo las pruebas relacionadas con la iteración actual se escribieron una vez. Entonces, lo que sugieres es perfectamente posible en ese tipo de escenario.

    
respondido por el 2 revsuser2567 02.04.2012 - 13:37
2
  • Luego intentas concentrarte en demasiadas cosas a la vez.
  • Mientras se implementa para hacer que todas las pruebas pasen, no tiene una versión funcional de su aplicación. Si tiene que implementar mucho, no tendrá una versión de trabajo durante mucho tiempo.
respondido por el magomi 02.04.2012 - 12:32
2

El ciclo Red-Green-Refactor es una lista de verificación para desarrolladores nuevos en TDD. Diría que es una buena idea seguir esta lista de verificación hasta que sepa cuándo debe seguirla y cuándo puede romperla (es decir, hasta que sepa no tenga que hacer esta pregunta en stackoverflow :)

Después de haber hecho TDD durante casi una década, puedo decirte que muy pocas veces, si es que alguna vez, escribo muchas pruebas fallidas antes de escribir el código de producción.

    
respondido por el Torbjörn Kalin 02.04.2012 - 13:24
1

Usted está describiendo BDD, donde algunas partes interesadas externas tienen una especificación ejecutable. Esto puede ser beneficioso si hay una especificación inicial predeterminada (por ejemplo, una especificación de formato, un estándar industrial o donde el programador no es el experto en dominios).

El enfoque normal es cubrir gradualmente más y más pruebas de aceptación, que es el progreso visible para el gerente del proyecto y el cliente.

Por lo general, estas pruebas se especifican y se ejecutan en un marco BDD como Cucumber, Fitnesse o algo similar.

Sin embargo, esto no es algo que se mezcle con sus pruebas de unidad, que están mucho más cerca de los detalles de la implementación de Nitty Gritty con una gran cantidad de casos de borde relacionados con API, problemas de inicialización, etc. muy centrados en el elemento bajo prueba , que es un artefacto de implementación .

La disciplina rojo-verde-refactor tiene muchos beneficios, y la única ventaja que puede esperar al escribirlos por adelantado es lograr un equilibrio.

    
respondido por el Tormod 02.04.2012 - 12:48
1

Una prueba a la vez: la principal ventaja es enfocarse en una cosa. Piense en el diseño primero en profundidad: puede profundizar y mantenerse enfocado con un bucle de retroalimentación rápido. ¡Aunque puedes perderte el alcance de todo el problema! Ese es el momento (grande) de refactorización que entra en juego. Sin ella, TDD no funciona.

Todas las pruebas: el análisis y el diseño pueden revelarle más del alcance del problema. Piense en el primer diseño de amplitud. Analiza el problema desde más ángulos y agrega información de la experiencia. Es intrínsecamente más difícil, pero puede generar un beneficio interesante, menos refactorización, si lo hace "lo suficiente". ¡Cuidado, es fácil de sobre-analizar y, sin embargo, perder completamente la marca!

En general, me resulta difícil recomendar preferir uno u otro, porque los factores son muchos: experiencia (especialmente con el mismo problema), conocimiento y habilidades de dominio, simpatía del código para refactorización, complejidad del problema ...

Supongo que si nos enfocamos más estrechamente en las aplicaciones comerciales típicas, entonces TDD con su enfoque rápido de casi prueba y error generalmente ganaría en términos de efectividad.

    
respondido por el MaR 02.04.2012 - 13:52
1

Suponiendo que su marco de prueba lo admita, lo que sugeriría es que en lugar de implementar las pruebas que desea utilizar, en lugar de eso, escriba las pruebas pendientes descriptivas que implementará más adelante. Por ejemplo, si su API debería hacer foo y bar pero no biz, simplemente agregue el siguiente código (este ejemplo está en rspec) para su conjunto de pruebas, luego ataque de uno en uno. Describe rápidamente tus pensamientos y puedes abordar todos tus problemas uno por uno. Cuando pasen todas las pruebas, sabrá cuándo ha abordado todos sus problemas que tuvo durante su braindump.

describe "Your API" do

  it "should foo" do
    pending "braindump from 4/2"
  end

  it "should bar" do
    pending "braindump from 4/2"
  end

  it "should not biz" do
    pending "braindump from 4/2"
  end

end
    
respondido por el Ransom Briggs 02.04.2012 - 17:33

Lea otras preguntas en las etiquetas