¿Las pruebas para el desarrollo basado en pruebas (TDD) son siempre pruebas unitarias?

41

Entiendo el desarrollo basado en pruebas hasta ahora, que solo se le permite escribir código productivo cuando tiene una prueba unitaria (roja) que falla. En base a esto, tengo la pregunta de si el enfoque basado en pruebas también se puede aplicar a otras formas de pruebas.

usuario1364368
fuente
66
No es raro usar más de un nivel diferente de rojo / verde / refactor anidado uno dentro del otro. Por ejemplo, puede seguir rojo / verde / refactor mientras escribe pruebas de aceptación / comportamiento, donde la fase 'verde' de la prueba de aceptación contiene múltiples iteraciones rojo / verde / refactor de pruebas unitarias.
Sean Burton
1
El título no coincide con el contenido de la pregunta. El título "son pruebas siempre pruebas unitarias " (respuesta: no, puede haber otros tipos de pruebas que no sean pruebas unitarias), el contenido pregunta "¿debe escribir la prueba primero?".
AnoE
@AnoE La primera oración del contenido es solo una declaración introductoria. La oración de segundos no pregunta si la prueba tiene que escribirse primero, pero si el enfoque TDD puede usarse para métodos de prueba que no sean TDD.
user1364368
@ user1364368, siéntase libre de reformular un poco la pregunta, al menos estaba confundido acerca de cuál es su intención en la primera lectura y la pregunta más votada, mientras que abordar ambas oraciones también comienza de manera prominente con la primera.
AnoE
@AnoE Cambié el comienzo de la segunda oración para dejar en claro cuál es la pregunta real.
user1364368

Respuestas:

27

Todo lo que TDD requiere de usted es que escriba una prueba fallida, luego modifique su código para que pase.

Por lo general, las "pruebas unitarias" son pequeñas y rápidas y prueban parte del código de forma aislada. Debido a que son rápidos, también hace que el bucle rojo / verde / refactorizador sea rápido. Sin embargo, solo sufren la prueba de piezas de forma aislada. Por lo tanto, también necesita otras pruebas (integración, aceptación, etc.). Sigue siendo una buena práctica seguir los mismos principios: escribir una prueba fallida, luego modificar el código para que funcione. Solo tenga en cuenta que generalmente son más lentos, por lo que pueden afectar el tiempo de ciclo rojo / verde / refactorizado.

David Arno
fuente
59

El ciclo de refactorización verde rojo se basa en un principio muy sólido:

Solo confíe en las pruebas que ha visto pasar y fallar.

Sí, eso también funciona con pruebas de integración automatizadas. También pruebas manuales. Diablos, funciona en probadores de baterías de automóviles. Así es como se prueba la prueba.

Algunos piensan que las pruebas unitarias abarcan lo más pequeño que se puede probar. Algunos piensan en algo que sea rápido de probar. TDD es más que solo el ciclo de refactorización verde rojo, pero esa parte tiene un conjunto muy específico de pruebas: no es la prueba que idealmente ejecutará una vez antes de enviar una colección de cambios. Son las pruebas que ejecutará cada vez que realice algún cambio. Para mí, esas son tus pruebas unitarias.

naranja confitada
fuente
1
Esta es también una de las razones por las que las pruebas negativas son importantes cuando se comprueba que se produce un error: desea asegurarse de que todo lo demás hubiera funcionado, por lo que tener dos pruebas (una que produzca el error esperado exacto, la otra que no produzca el error) al lado de mutuamente ayuda a aumentar la confianza de que en el futuro este estado rojo / verde continuará.
Matthieu M.
12

Sin embargo, me pregunto si el enfoque basado en pruebas también se puede aplicar a otras formas de pruebas.

Sí, y un enfoque bien conocido que hace esto es el desarrollo impulsado por el comportamiento . Las pruebas que se generan a partir de la especificación formal en BDD podrían denominarse "pruebas unitarias", pero generalmente no serán de tan bajo nivel como en TDD real, probablemente se ajustarán mejor al término "pruebas de aceptación".

Doc Brown
fuente
8

Entiendo el desarrollo basado en pruebas hasta ahora, que solo se le permite escribir código productivo cuando tiene una prueba unitaria (roja) que falla.

No. Solo se le permite escribir el código más simple posible para cambiar el mensaje de la prueba. No dice nada sobre qué tipo de prueba.

De hecho, probablemente comenzará escribiendo una prueba de aceptación fallida (roja) para un criterio de aceptación, más precisamente, escriba la prueba de aceptación más simple que podría fallar; luego ejecuta la prueba, observa cómo falla y verifica que falla por la razón correcta. Luego, escribe una prueba funcional fallida para una porción de funcionalidad de ese criterio de aceptación, nuevamente, escribe la prueba funcional más simple que podría fallar, ejecutarla, verla fallar y verificar que falla por la razón correcta. Luego, escribe una prueba unitaria fallida, la prueba unitaria más simple que posiblemente podría fallar, ejecútela, mírela fallar, verifique que falle por la razón correcta.

Ahora , escribe el código de producción más simple que posiblemente podría cambiar el mensaje de error. Ejecute la prueba nuevamente, verifique que el mensaje de error haya cambiado, que haya cambiado en la dirección correcta y que el código haya cambiado el mensaje por la razón correcta. (Idealmente, el mensaje de error ya debería haber desaparecido, y la prueba debería pasar, pero la mayoría de las veces, es mejor dar pequeños pasos para cambiar el mensaje en lugar de tratar de pasar la prueba de una vez; esa es la razón ¡Por qué los desarrolladores de marcos de prueba gastan tanto esfuerzo en sus mensajes de error!)

Una vez que aprueba la prueba unitaria, refactoriza su código de producción bajo la protección de sus pruebas. (Tenga en cuenta que en este momento, la prueba de aceptación y la prueba funcional aún fallan, pero está bien, ya que solo está refactorizando unidades individuales que están cubiertas por pruebas unitarias).

Ahora crea la siguiente prueba unitaria y repite lo anterior, hasta que también pase la prueba funcional. Bajo la protección de la prueba funcional, ahora puede realizar refactorizaciones en varias unidades.

Este ciclo intermedio ahora se repite hasta que pase la prueba de aceptación, momento en el que ahora puede realizar refactorizaciones en todo el sistema.

Ahora, elige el siguiente criterio de aceptación y el ciclo externo comienza nuevamente.

Kent Beck, el "descubridor" de TDD (no le gusta el término "inventor", dice que la gente ha estado haciendo esto todo el tiempo, simplemente le dio un nombre y escribió un libro al respecto) utiliza una analogía de la fotografía y llama a esto "acercar y alejar".

Nota: no siempre necesita tres niveles de pruebas. Tal vez, a veces necesitas más. Más a menudo, necesitas menos. Si sus piezas de funcionalidad son pequeñas y sus pruebas funcionales son rápidas, puede sobrevivir sin ellas (o con menos pruebas unitarias). A menudo, solo necesita pruebas de aceptación y pruebas unitarias. O bien, sus criterios de aceptación son tan precisos que sus pruebas de aceptación son pruebas funcionales.

Kent Beck dice que si tiene una prueba funcional rápida, pequeña y enfocada, primero escribirá las pruebas unitarias, dejará que las pruebas unitarias conduzcan el código y luego elimine (algunas de) las pruebas unitarias nuevamente que cubran el código que también es cubierto por la prueba funcional rápida. Recuerde: el código de prueba también es un código que necesita ser mantenido y refactorizado, ¡cuanto menos haya, mejor!

Sin embargo, me pregunto si el enfoque basado en pruebas también se puede aplicar a otras formas de pruebas.

Realmente no aplicas TDD a las pruebas. Lo aplicas a todo tu proceso de desarrollo. Eso es lo que significa la parte "impulsada" de Test- Driven -Development: todo su desarrollo es impulsado por pruebas. Las pruebas no solo controlan el código que escribes, sino que también controlan qué código escribir y qué código escribir a continuación. Impulsan su diseño. Te dicen cuando hayas terminado. Te dicen en qué trabajar a continuación. Le informan sobre fallas de diseño en su código (cuando las pruebas son difíciles de escribir).

Keith Braithwaite ha creado un ejercicio que llama TDD como si lo quisieras decir . Consiste en un conjunto de reglas (basadas en las Tres Reglas de TDD del Tío Bob Martin , pero mucho más estrictas) que debe seguir estrictamente y que están diseñadas para guiarlo hacia la aplicación de TDD de manera más rigurosa. Funciona mejor con la programación de pares (para que tu pareja pueda asegurarse de que no estás rompiendo las reglas) y un instructor.

Las reglas son:

  1. Escriba exactamente una prueba nueva, la prueba más pequeña que pueda que parezca apuntar en la dirección de una solución
  2. Véalo fallar; las fallas de compilación cuentan como fallas
  3. Haga que la prueba de (1) pase escribiendo el menor código de implementación que pueda en el método de prueba .
  4. Refactorizar para eliminar la duplicación y, de lo contrario, según sea necesario para mejorar el diseño. Sea estricto sobre el uso de estos movimientos:
    1. desea un nuevo método: espere hasta el momento de refactorización, luego ... cree nuevos métodos (que no sean de prueba) haciendo uno de estos, y de ninguna otra manera:
      • preferido: hacer Extraer método en el código de implementación creado según (3) para crear un nuevo método en la clase de prueba, o
      • si debe: mover el código de implementación según (3) a un método de implementación existente
    2. desea una nueva clase: espere hasta el momento de refactorización, luego ... cree clases que no sean de prueba para proporcionar un destino para un Método Move y sin ninguna otra razón
    3. llenar clases de implementación con métodos haciendo Move Method, y de ninguna otra manera

Estas reglas están destinadas a ejercer TDD. No están destinados a hacer TDD en producción (aunque nada impide que lo pruebes). Pueden sentirse frustrantes porque a veces parecerá que das miles de pequeños pasos sin hacer ningún progreso real.

Jörg W Mittag
fuente
2

TDD no se limita en absoluto a lo que la comunidad tradicional de pruebas de software llama "pruebas unitarias". Este malentendido muy común es el resultado de la desafortunada sobrecarga de Kent Beck del término "unidad" cuando describe su práctica de TDD. Lo que quiso decir con "prueba de unidad" fue una prueba que se ejecuta de forma aislada. No depende de otras pruebas. Cada prueba debe configurar el estado que necesita y hacer cualquier limpieza cuando haya terminado. Es en este sentido que una prueba unitaria en el sentido TDD es una unidad. Es independiente. Se puede ejecutar solo o se puede ejecutar junto con cualquier otra prueba unitaria en cualquier orden.

Referencia : "Test Driven Development By Example", por Kent Beck

Kent Beck describe lo que quiere decir con "prueba de unidad" en el Capítulo 32 - Dominar TDD

Jason Desrosiers
fuente
1

No he leído libros sobre él, ni sigo completamente las prácticas "estándar" de TDD todo el tiempo, pero en mi opinión, el punto principal de la filosofía de TDD, con el que estoy completamente de acuerdo, es que primero debe definir el éxito . Esto es importante en todos los niveles de diseño, desde "¿Cuál es el objetivo de este proyecto?" a "¿Cuáles deberían ser las entradas y salidas de este pequeño método?"

Hay muchas maneras de hacer esta definición de éxito. Uno útil, particularmente para esos métodos de bajo nivel con muchos casos extremos, es escribir pruebas en código. Para algunos niveles de abstracción, puede ser útil solo escribir una nota rápida sobre el objetivo del módulo o lo que sea, o incluso simplemente revisar mentalmente (o preguntarle a un compañero de trabajo) para asegurarse de que todo tenga sentido y esté en un estado correcto. lugar lógico A veces es útil describir una prueba de integración en el código (y, por supuesto, eso ayuda a uno a automatizarla), y a veces es útil solo definir un plan de prueba rápido razonable que pueda usar para asegurarse de que todos los sistemas funcionen juntos de la manera que usted están esperando

Pero independientemente de las técnicas o herramientas específicas que esté utilizando, en mi opinión, la clave para eliminar la filosofía TDD es que la definición del éxito ocurre primero. De lo contrario, lanzarás el dardo y luego pintarás la diana donde sea que aterrice.


fuente
1

En la charla Desarrollo impulsado por pruebas: Esto no es lo que queríamos decir Steve Freeman muestra la siguiente diapositiva del panorama general de TDD (ver la imagen a continuación) Esto incluye un paso "Escribir una prueba de punta a punta que falla", seguido de "Escribir una prueba de unidad que falla". (Haga clic para acercar, está en la parte superior derecha)

Entonces, no en TDD, las pruebas no siempre son pruebas unitarias.

Y sí, puede (y tal vez debería) comenzar con una prueba de nivel superior de extremo a extremo que falla antes de escribir su primera prueba unitaria. Esta prueba describe el comportamiento que desea lograr. Esto genera cobertura en más niveles de la pirámide de prueba . Adrian Sutton explica la experiencia de LMAX que muestra que las pruebas de extremo a extremo pueden desempeñar un papel importante y valioso .

ingrese la descripción de la imagen aquí

Niels van Reijmersdal
fuente
-1

No, no se puede aplicar a otro tipo de pruebas, por una simple razón práctica: otros tipos de pruebas tardan demasiado en ejecutarse.

El ciclo TDD típico es: prueba de falla de escritura, implemento, código de refactorización. Los pasos intermedios son la construcción y ejecución de pruebas, y esto debe ser muy rápido. Si no lo están, la gente comenzaría a omitir los pasos y ya no estarás haciendo TDD.

BЈовић
fuente
1
Esto es incorrecto: dependiendo del programa y la prueba (y el idioma), las pruebas de integración de extremo a extremo pueden ejecutarse fácilmente en menos de 3 segundos. Es completamente posible ejecutar un conjunto completo de pruebas de extremo a extremo en muy poco tiempo, incluso si está bien diseñado. Entonces "no se puede" es bastante fuerte.
Jonathan Cast
@jcast Nunca vi nada más que sea tan rápido. Mis pruebas funcionales en mi proyecto anterior tomaron 30 segundos, y eso es rápido. Integración aún más larga. En mi caso, nada más tenía sentido. Además, las pruebas unitarias son las más rápidas de todo tipo de pruebas, por lo tanto, tiene sentido usarlas.
Bћовић