¿Por qué funciona TDD? [cerrado]

92

El desarrollo basado en pruebas (TDD) es grande en estos días. A menudo lo veo recomendado como una solución para una amplia gama de problemas aquí en Programmers SE y otros lugares. Me pregunto por qué funciona.

Desde el punto de vista de la ingeniería, me desconcierta por dos razones:

  1. El enfoque de "prueba de escritura + refactorización hasta pasar" parece increíblemente anti-ingeniería. Si los ingenieros civiles usaran ese enfoque para la construcción de puentes, o los diseñadores de automóviles para sus automóviles, por ejemplo, estarían remodelando sus puentes o automóviles a un costo muy alto, y el resultado sería un desastre reparado sin una arquitectura bien pensada . La directriz "refactorizar hasta pasar" a menudo se toma como un mandato para olvidar el diseño arquitectónico y hacer lo que sea ​​necesario para cumplir con la prueba; en otras palabras, la prueba, en lugar del usuario, establece el requisito. En esta situación, ¿cómo podemos garantizar buenas "ilidades" en los resultados, es decir, un resultado final que no solo sea correcto sino también extensible, robusto, fácil de usar, confiable, seguro, etc. Esto es lo que suele hacer la arquitectura.
  2. Las pruebas no pueden garantizar que un sistema funcione; solo puede mostrar que no lo hace. En otras palabras, las pruebas pueden mostrarle que un sistema contiene defectos si falla una prueba, pero un sistema que pasa todas las pruebas no es más seguro que un sistema que las falla. La cobertura de la prueba, la calidad de la prueba y otros factores son cruciales aquí. Las falsas sensaciones de seguridad que un resultado "totalmente verde" produce para muchas personas han sido reportadas en las industrias civiles y aeroespaciales como extremadamente peligrosas, porque pueden interpretarse como "el sistema está bien", cuando realmente significa que "el sistema es tan bueno". como nuestra estrategia de prueba ". A menudo, la estrategia de prueba no se verifica. ¿O quién prueba las pruebas?

En resumen, estoy más preocupado por el bit "conducido" en TDD que por el bit "prueba". La prueba está perfectamente bien; lo que no entiendo es conducir el diseño al hacerlo.

Me gustaría ver respuestas que contengan las razones por las cuales TDD en ingeniería de software es una buena práctica, y por qué los problemas que he explicado anteriormente no son relevantes (o no lo suficientemente relevantes) en el caso del software. Gracias.

CesarGon
fuente
53
Los puentes, automóviles y otros diseños físicos no son tan maleables como el software. Esta es una distinción importante y significa que las comparaciones entre software e ingeniería real no siempre son relevantes. Lo que funciona para los puentes podría no funcionar para el software, y viceversa.
Lars Wirzenius
99
Estoy un poco de acuerdo con tus dudas. Por ejemplo, debo confesar que tengo la impresión de que tener un conjunto de pruebas puede tener como efecto secundario una atención "suavizada" de alguna manera al escribir código. Por supuesto, las pruebas son algo bueno (obligatorio si desea tener la posibilidad de refactorizar), pero solo si complementan la atención a los detalles, los casos límite, la eficiencia o la extensibilidad y no si lo reemplazan.
6502
2
@ 6502: ¡Por supuesto! TDD no es una bala de plata y no resolverá todos los problemas que surjan durante el desarrollo de software. Sin embargo, es un método útil para organizar el flujo de trabajo. Por ejemplo, puede imponer un requisito de que todos los casos fronterizos estén cubiertos por pruebas. Todavía necesita saber cuáles son estos casos fronterizos, pero ahora también tiene una herramienta para verificar si su código los trata correctamente.
Mchl
2
@CesarGon, también podría ser interesante en esta pregunta que hice en SO hace algún tiempo ... No es exactamente TDD, pero está relacionado ... Algunas respuestas muy esclarecedoras allí.
AviD
66
Qué sorprendente que un análogo de ingeniería civil / desarrollo de software no aguante. En la misma línea, a menudo me he dado cuenta de que no puedo cocinar panqueques de la misma manera que cortar el césped.

Respuestas:

66

Creo que hay una idea falsa aquí. En el diseño de software, el diseño está muy cerca del producto. En ingeniería civil, arquitectura, el diseño se desacopla del producto real: hay planos que contienen el diseño, que luego se materializan en el producto terminado, y estos se separan por una gran cantidad de tiempo y esfuerzo.

TDD está probando el diseño. Pero todos los diseños de automóviles y edificios también se prueban. Primero se calculan las técnicas de construcción, luego se prueban a menor escala, luego se prueban a mayor escala, antes de colocarlas en un edificio real. Cuando inventaron las vigas en H y la carga, por ejemplo, descanse asegurado de que esto se ha intentado e intentado nuevamente antes de que realmente construyan el primer puente con él.

Los diseños de automóviles también se prueban, diseñando prototipos, y sí, ciertamente ajustando cosas que no son exactamente correctas, hasta que cumpla con las expectativas. Sin embargo, parte de este proceso es más lento porque, como dijiste, no puedes perder el tiempo con el producto. Pero cada rediseño de un automóvil se basa en las experiencias aprendidas de los antiguos, y cada edificio tiene alrededor de miles de años de fundamentos detrás de la importancia del espacio, la luz, el aislamiento, la resistencia, etc. Los detalles se cambian y mejoran, tanto en los edificios. y en rediseños para los más nuevos.

Además, se prueban las piezas. Quizás no exactamente en el mismo estilo que el software, pero las partes mecánicas (ruedas, encendedores, cables) generalmente se miden y se someten a estrés para saber que los tamaños son correctos, no se ven anormalidades, etc. Pueden ser radiografiados o láser. medido, golpean los ladrillos para detectar los que están rotos, pueden ser probados en una configuración u otra, o dibujan una representación limitada de un grupo grande para realmente ponerlo a prueba.

Esas son todas las cosas que puede implementar con TDD.

Y de hecho, las pruebas no son garantía. Los programas se bloquean, los autos se descomponen y los edificios comienzan a hacer cosas divertidas cuando sopla el viento. Pero ... 'seguridad' no es una pregunta booleana. Incluso cuando no puede incluir todo, poder cubrir, digamos, el 99% de las eventualidades es mejor que cubrir solo el 50%. No probar y luego descubrir que el acero no se ha asentado bien y es frágil y se rompe al primer golpe de un martillo cuando acaba de levantar su estructura principal es un simple desperdicio de dinero. El hecho de que haya otras inquietudes que aún podrían dañar el edificio no hace que sea menos estúpido permitir que un defecto fácilmente evitable derribe su diseño.

En cuanto a la práctica de TDD, eso es una cuestión de equilibrio. El costo de hacerlo de una manera (por ejemplo, no probar, y luego recoger las piezas más tarde), versus el costo de hacerlo de otra manera. Siempre es un equilibrio. Pero no piense que otros procesos de diseño no tienen pruebas y TDD en su lugar.

Inca
fuente
77
+1 por hablar sobre dónde se realizan las pruebas en la fabricación. Gran punto
Adam Lear
11
Dices "las piezas se prueban". Claro, pero no diseñado para pruebas. Una parte de un avión no está diseñada de manera probada, sino de una manera arquitectónica y de gran diseño por adelantado. Las similitudes con TDD son inexistentes aquí.
CesarGon
3
Además de eso: TDD es, en mi opinión, principalmente sobre formas de asegurarse de que puede verificar partes en lugar de un gran 'todo o nada' al final. Pero el adagio de TDD, "construir una prueba primero" no pretende ser "hacer una prueba antes de pensar en lo que quiere lograr". Porque pensar en una prueba ES parte del diseño. Especificar lo que quieres que haga esa parte exacta es diseñar. Antes de comenzar a escribir, ya ha realizado algunos diseños. (De esa manera, creo que el término 'diseño impulsado por pruebas' implica de manera engañosa un camino unidireccional, donde realmente es un ciclo de retroalimentación).
Inca
2
+1: el software es puramente diseño. La analogía del puente en la pregunta está completamente equivocada. TDD se aplica totalmente a las pruebas de unidades externas. El diseño dirigido por prueba se aplica a todas las capas de diseño.
S.Lott
3
@CesarGon: No, TDD está impulsando el DESARROLLO mediante pruebas. Eso es diferente a conducir el diseño. El diseño dicta cómo usaría el sistema y, por lo tanto, qué pruebas necesitaría implementar para replicar ese comportamiento. Sin embargo, implementar esas pruebas a menudo lo ayuda a refinar el diseño.
deworde
26

En mi opinión, la mayoría de las historias de éxito de TDD son falsas y solo para fines de marketing. Puede haber muy poco éxito con él, pero solo para aplicaciones pequeñas. Estoy trabajando en una gran aplicación de Silverlight donde se utilizan los principios TDD. La aplicación tiene cientos de pruebas pero aún no es estable. Varias partes de la aplicación no son comprobables debido a las complejas interacciones del usuario. Pruebas resultantes con muchos simulacros y código difícil de entender.

Inicialmente, cuando probamos TDD, todo parece estar bien. Pude escribir muchas pruebas y simular las partes que son difíciles para una prueba unitaria. Una vez que tenga una buena cantidad de código y se requiera un cambio de interfaz, estará jodido. Se deben corregir muchas pruebas y reescribirá más pruebas que el cambio real en el código.

Peter Norvig explica su punto de vista sobre TDD en el libro Coders At Work.

Seibel: ¿Qué pasa con la idea de usar pruebas para impulsar el diseño?

Norvig: Veo las pruebas más como una forma de corregir errores que como una forma de diseño. Este enfoque extremo de decir: "Bueno, lo primero que haces es escribir una prueba que diga que obtengo la respuesta correcta al final", y luego la ejecutas y ves que falla, y luego dices: "¿Qué hago? ¿Necesito lo siguiente? ”, esa no me parece la forma correcta de diseñar algo para mí. Parece que solo si fuera tan simple que la solución estuviera preordenada tendría sentido. Creo que primero tienes que pensarlo. Tienes que decir: "¿Cuáles son las piezas? ¿Cómo puedo escribir pruebas para piezas hasta que sepa cuáles son algunas de ellas? ”Y luego, una vez que hayas hecho eso, es una buena disciplina tener pruebas para cada una de esas piezas y comprender bien cómo interactúan entre sí. y los casos límite y así sucesivamente. Todos deberían tener pruebas. Pero no creo que maneje todo el diseño diciendo: "Esta prueba ha fallado".

Navaneeth KN
fuente
77
Ahora, si le cuenta estos hechos a las personas y consultores de TDD, la respuesta que obtendrá sería:well, you haven't done TDD right!
Navaneeth KN el
10
Y tendrían razón. Estamos haciendo BDD / TDD en un sistema de muy alto volumen, y ha estado funcionando bien. Las pruebas están ahí para decirle que rompió el comportamiento esperado. Si vas a cambiar esto más tarde "rompiendo" las pruebas, de hecho lo estás haciendo mal. Las pruebas deben cambiarse primero para solidificar el NUEVO comportamiento del sistema y luego cambiarlo. Y sí, si lo estás haciendo bien, escribes tus pruebas comenzando con "qué necesita hacer esto" y el proceso de escribir la prueba te ayuda a pensar "qué necesita TI para hacer su trabajo". Ah, y nunca se utilizaron consultores ...
Andy
44
Hacer muchas pruebas no lo exime de crear un diseño adecuado. Un diseño altamente acoplado, independientemente de cuántas pruebas se construyan a su alrededor, es y siempre será frágil. Las pruebas de integración en este diseño pueden empeorar todo aún más.
Newtopian
3
No se trata de hacerlo mal o de ser un diseño altamente acoplado. El hecho es que las interfaces cambian. Eso significa que todas las pruebas que usan esa interfaz deben cambiar. En sistemas grandes, mantener las pruebas sincronizadas con los cambios requeridos puede comenzar a abrumar la implementación. Esto se convierte en un problema aún mayor si está haciendo un desarrollo ágil ya que las posibilidades de cambios en la interfaz son mucho más probables. Es curioso cómo cuando las metodologías no funcionan, los defensores de la metodología insisten en que lo estás haciendo mal. Es más probable que la metodología no sea adecuada para todos los dominios problemáticos.
Dunk
2
En mi experiencia, hacer TDD funciona para pequeñas aplicaciones o módulos. Cuando tengo que trabajar en algo complejo, TDD me ralentiza porque me obliga a escribir una especificación detallada (ejecutable) antes de tener clara la imagen general: así que me pierdo en los detalles demasiado pronto, y a menudo tengo que hacerlo. descartar un montón de pruebas si descubro que no necesito ciertas clases (todavía estoy jugando con el diseño). En tales casos, prefiero obtener un diseño general razonable primero, y luego desarrollar los detalles de implementación (posiblemente usando TDD).
Giorgio,
25

Test Driven Design me funciona por las siguientes razones:

Es una forma ejecutable de la especificación.

Esto significa que puede ver en los casos de prueba:

  1. QUE el código que se llama completa la especificación ya que los resultados esperados están ahí en los casos de prueba. La inspección visual (que espera que pasen los casos de prueba) puede decir inmediatamente "oh, esta prueba verifica que llamar a factura a la Compañía dada esta situación, debería tener ESO resultado".
  2. CÓMO debe llamarse el código. Los pasos reales necesarios para realizar las pruebas se especifican directamente sin ningún andamiaje externo (las bases de datos se burlan, etc.).

Primero escribes la vista desde afuera.

Con frecuencia, el código se escribe de una manera en la que primero resuelve el problema y luego piensa en cómo debe llamarse el código que acaba de escribir. Con frecuencia, esto proporciona una interfaz incómoda porque con frecuencia es más fácil "simplemente agregar una bandera", etc. Al pensar en "tenemos que hacer ESTO para que las cajas de prueba se vean así" al principio, usted da la vuelta. Esto dará una mejor modularidad, ya que el código se escribirá de acuerdo con la interfaz de llamada, no al revés.

Por lo general, esto también dará como resultado un código más limpio que requiere menos documentación explicativa.

Terminas más rápido

Como tiene la especificación en forma ejecutable, habrá terminado cuando pase el conjunto de pruebas completo. Puede agregar más pruebas a medida que aclara las cosas en un nivel más detallado, pero como principio básico tiene un indicador muy claro y visible del progreso y cuando haya terminado.

Esto significa que puede saber cuándo el trabajo es necesario o no (ayuda a pasar una prueba) y termina necesitando hacer menos.

Para quienes lo consideren útil, les animo a usar TDD para su próxima rutina de biblioteca. Configure lentamente una especificación ejecutable y haga que el código pase las pruebas. Cuando termine, la especificación ejecutable estará disponible para todos los que necesiten ver cómo invocar la biblioteca.

Estudio reciente

"Los resultados de los estudios de caso indican que la densidad de defectos previos al lanzamiento de los cuatro productos disminuyó entre 40% y 90% en relación con proyectos similares que no utilizaron la práctica de TDD. Subjetivamente, los equipos experimentaron un aumento de 15 a 35% en tiempo de desarrollo inicial después de adoptar TDD ". ~ Resultados y experiencias de 4 equipos industriales

Dave Jarvis
fuente
55
Añadiría a esto que en realidad TIENES una directriz algo razonable y clara sobre cuándo has terminado. Sin algún procedimiento claro para verificar objetivamente que ha completado la tarea en cuestión, es difícil saberlo. Mi propia experiencia incluye muchas horas y días desperdiciados "negociando" si una tarea se ha completado y un movimiento continuo y constante de la línea. Esto afecta a todos los niveles de gestión de proyectos, incluida la programación, ¿cómo puede programar tal tarea? Los objetivos más claros con un tiempo de respuesta más rápido aumentan el rendimiento Y la comunicación.
Edward Strange el
Esta debería ser la respuesta aceptada.
Niing
19

El proceso de creación de software no es el proceso de escribir el código. Ningún proyecto de software debe comenzar sin un plan de "amplio alcance" primero. Al igual que un proyecto de unir dos orillas de un río necesita un plan de este tipo primero.

El enfoque TDD se relaciona (principalmente) con las pruebas unitarias, al menos así es como las personas tienden a pensar en ello, es decir, crear los bits de código de software de más bajo nivel. Cuando todas las características y comportamientos ya se han definido y realmente sabemos lo que queremos lograr.

En ingeniería estructural se parece un poco a esto:

'Tenemos estas dos piezas de metal conectadas entre sí, y la conexión necesita sostener fuerzas de corte en el orden de x. Probemos qué método de conexión es el mejor para hacer esto '

Para probar si el software funciona como un todo, diseñamos otro tipo de pruebas como pruebas de usabilidad, pruebas de integración y pruebas de aceptación. Estos también deben definirse antes de que comience el trabajo real de escritura del código, y se realizan después de que las pruebas unitarias sean verdes.

Ver Modelo V: http://en.wikipedia.org/wiki/V-Model_%28software_development%29

Veamos cómo funcionaría para un puente:

  1. Un gobierno local le dice a una empresa de construcción de puentes: "Necesitamos un puente para conectar estos dos puntos. El puente debe ser capaz de permitir una cantidad n de tráfico por hora y estar listo para el 21 de diciembre de 2012". Esta es una definición de prueba de aceptación. La empresa no obtendrá la cantidad total (o ninguna) de dinero, si no puede pasar esa prueba.

  2. La gestión de la empresa decide el cronograma del proyecto. Establecieron equipos de trabajo y establecieron objetivos para cada equipo. Si los equipos no cumplen con estos objetivos, el puente no se construirá a tiempo. Sin embargo, hay cierto nivel de flexibilidad aquí. Si uno de los equipos tiene algunos problemas, la compañía puede compensarlo cambiando los requisitos, cambiando los subcontratistas, contratando a más personas, etc. para que todo el proyecto cumpla con el objetivo establecido en el punto 1.

  3. Dentro de un equipo responsable de diseñar componentes de puentes particulares, se ve en el ejemplo que he dado anteriormente. A veces, la solución es obvia, porque tenemos un gran conocimiento sobre la construcción de puentes (es como usar una biblioteca bien probada en el desarrollo de software; simplemente asume que funciona como se anuncia). A veces es necesario crear varios diseños y probarlos para elegir el mejor. Aún así, los criterios sobre los cuales se prueba el componente se conocen de antemano.

Mchl
fuente
Si te entiendo correctamente, estás diciendo que TDD está bien siempre y cuando (a) se use solo para pruebas unitarias, y (b) también esté acompañado de otros enfoques de prueba. Si este es el caso, puede abordar el punto número 2 en el OP. ¿Cómo abordaría el punto número 1?
CesarGon
@CesarGon: TDD también funciona muy bien para pruebas de integración.
sevenseacat
El punto 1 se reduce a la acción, que antes de que se acepte el proyecto final para un automóvil o un puente, pasa por muchas reiteraciones durante las cuales todos sus detalles se revisan y prueban en relación con los requisitos impuestos por el 'plan de amplio alcance'. Se realiza principalmente en papel (o en la memoria de la computadora), porque es más barato en este caso, pero tenga en cuenta que a menudo se construyen prototipos físicos tanto de la construcción completa (quizás no en el caso del puente) como de sus componentes.
Mchl
@Karpie: ¡Y también para las pruebas de aceptación! Debe saber de antemano qué se requiere para que su trabajo sea aceptado por el cliente.
Mchl
1
OK entonces. Casi el primer equipo en comenzar el trabajo es un equipo de arquitectos a quienes se les pide que diseñen un puente capaz de cumplir con los criterios de los clientes, a la vez que también es barato y posiblemente se vea bien y no caiga en la primera ráfaga de viento más fuerte. El equipo puede proponer algunos diseños aproximados que cumplan más o menos con estos criterios, luego seleccionar uno y trabajar en él con más detalles, repetir, repetir, repetir hasta que el diseño esté listo (es decir, cumpla con los criterios dados y sea lo suficientemente detallado para que pueden comenzar otras etapas del proyecto)
Mchl
18

En mi opinión, TDD funciona porque

  • Te obliga a definir qué quieres que haga la unidad antes de decidir sobre la implementación a un nivel de precisión que generalmente no está cubierto por ninguna especificación o requisito
  • Hace que su código sea inherentemente reutilizable, ya que debe usarlo tanto en pruebas como en escenarios de producción
  • Te alienta a escribir código en un eaiser más pequeño para probar fragmentos que tienden a conducir a mejores diseños

Específicamente en los puntos que planteas

  • El código es más maleable que el ladrillo o el acero, por lo que es más barato modificarlo. Es más barato aún si tiene pruebas para asegurarse de que el comportamiento no cambia
  • TDD no es una excusa para no hacer diseño: una arquitectura de alto nivel todavía es recomendable, pero no con demasiados detalles. Se desaconseja el diseño Big Up Front, pero se recomienda hacer solo el diseño suficiente
  • TDD no puede garantizar que un sistema funcione, pero evita que se filtren muchos pequeños errores que de otro modo se perderían. Además, debido a que generalmente fomenta un mejor código factorizado, a menudo es más fácil de entender, por lo que es menos probable que tenga errores
Gavin Clarke
fuente
3
También debe agregar que a medida que se descubren defectos, puede asegurarse de que no se repitan, ya que agregará otra prueba.
Andy
16

TL; DR

La programación sigue siendo una actividad de diseño, no es construcción. Escribir pruebas unitarias después del hecho solo confirma que el código hace lo que hace, no que hace algo útil. Las fallas en las pruebas son el valor real porque le permiten detectar errores temprano.

Code Is Design

En el Capítulo 7 de PPP, "Tío Bob" habla sobre este tema directamente. Muy temprano en el capítulo, hace referencia a un excelente artículo de Jack Reeves en el que propone que el código es diseño (el enlace va a una página que recoge los tres artículos sobre el tema).

Lo interesante de este argumento es que señala que, a diferencia de otras disciplinas de ingeniería donde la construcción es una actividad muy costosa, la construcción de software es relativamente gratuita (compila con éxito en tu IDE y tienes tu software integrado). Si ve el código escrito como una actividad de diseño en lugar de una actividad de construcción, entonces el ciclo refactor rojo-verde es básicamente un ejercicio de diseño. Su diseño evoluciona a medida que escribe pruebas, el código para satisfacerlas y refactoriza para integrar el nuevo código en el sistema existente.

TDD como especificación

Las pruebas unitarias que escribe para TDD son una traducción directa de la especificación tal como la comprende. Al escribir código que satisfaga mínimamente su especificación (hace que sus pruebas se vuelvan verdes), todo el código que ha escrito está ahí para un propósito específico. Si se cumple o no ese propósito se valida mediante una prueba repetible.

Escribir pruebas para la funcionalidad

Un error común en las pruebas unitarias ocurre cuando escribe las pruebas después del código, termina probando que el código hace lo que hace. En otras palabras, verás pruebas como esta

public class PersonTest:Test
{
   [Test]
   TestNameProperty()
   {
      var person=new Person();
      person.Name="John Doe";
      Assert.AreEqual("John Doe", person.Name);
   }
}

Si bien supongo que este código podría ser útil (asegúrese de que alguien no haya hecho algo obsceno con una propiedad simple). No sirve para validar una especificación. Y como dijiste, escribir este tipo de pruebas solo te lleva muy lejos.

Mientras que el verde es bueno, el valor está en el rojo. Tuve mi primer momento verdadero "ajá" en TDD cuando recibí una falla inesperada en la prueba. Tenía un conjunto de pruebas que tenía para un marco que estaba construyendo. Añadiendo una nueva característica, escribí una prueba para ello. Luego escribió el código para hacer pasar la prueba. Compilar, probar ... obtuvo un verde en la nueva prueba. Pero también obtuve un rojo en otra prueba que no esperaba que se pusiera rojo.

Mirando el fracaso, suspiro de alivio porque dudo que hubiera atrapado ese error por bastante tiempo si no hubiera tenido esa prueba en su lugar. Y fue un error MUY desagradable tener. Afortunadamente, tuve la prueba y me dijo exactamente lo que tenía que hacer para corregir el error. Sin la prueba, habría seguido construyendo mi sistema (con el error infectando a otros módulos que dependían de ese código) y para cuando se descubriera el error, habría sido una tarea importante solucionarlo correctamente.

El verdadero beneficio de TDD es que nos permite realizar cambios con abandono imprudente. Es como una red de seguridad para la programación. Piense en lo que sucedería si un trapecista comete un error y cae. Con la red, es un error embarazoso. Sin eso, es una tragedia. En el mismo sentido, TDD le evita convertir los errores descabellados en desastres que matan proyectos.

Michael Brown
fuente
44
El valor de las pruebas rojas que detectan errores es un atributo de las Pruebas unitarias en general, no de TDD específicamente.
Robert Harvey
2
Tienes razón en ese punto. Pero la probabilidad de que hubiera tenido ese error específico cubierto con pruebas unitarias post-hoc es menor.
Michael Brown
1
¿Puedes apoyar esa afirmación con alguna evidencia, datos o análisis sólido?
CesarGon
1
@CesarGon este estudio , mientras que los programadores que trabajan en un proyecto pequeño, sugiere que los desarrolladores que usan TDD producen código con una mejor cobertura de prueba que aquellos que prueban después del hecho (92% -98% frente a 80% -90%) y, en consecuencia, capturan más defectos durante el desarrollo (18% menos defectos encontrados en el código producido usando TDD).
Jules
11

No encontrará a nadie que defienda Test Driven Development, o incluso Test Driven Design (son diferentes), que dice que las pruebas prueban las aplicaciones. Así que vamos a llamar a eso un hombre de paja y listo.

No encontrará a nadie a quien no le guste o no esté impresionado por TDD que diga que las pruebas son una pérdida de tiempo y esfuerzo. Aunque las pruebas no prueban las aplicaciones, son bastante útiles para encontrar errores.

Dicho esto, ninguna de las partes está haciendo nada diferente con respecto a la realización de pruebas en el software. Ambos están haciendo pruebas. Ambos confían en las pruebas para encontrar tantos errores como sea posible, y ambos usan pruebas para verificar que un programa de software funciona tan bien como se puede descubrir en ese momento. Nadie con media pista vende software sin probar y nadie con media pista espera que las pruebas vayan a dejar el código que venden completamente sin errores.

Entonces, la diferencia entre TDD y no TDD no es que se estén haciendo pruebas. La diferencia está en cuando se escriben las pruebas. En TDD, las pruebas se escriben ANTES del software. En las pruebas que no son TDD se escriben después o en concierto con el software.

El problema que he visto con respecto a este último es que las pruebas tienden a apuntar al software que se escribe más que el resultado o la especificación deseados. Incluso con el equipo de prueba separado del equipo de desarrollo, el equipo de prueba tiende a mirar el software, jugar con él y escribir pruebas que lo apunten.

Una cosa que han notado una y otra vez los que estudian el éxito del proyecto es la frecuencia con que un cliente diseña lo que quiere, la gente de desarrollo se escapa y escribe algo, y cuando regresa al cliente diciendo "hecho" Resulta ser total y completamente NO lo que el cliente solicitó. "Pero pasa todas las pruebas ..."

El objetivo de TDD es romper este "argumento circular" y proporcionar una base para las pruebas que prueban el software que no es el software en sí. Las pruebas se escriben para apuntar al comportamiento que el "cliente" quiere. El software se escribe para pasar esas pruebas.

Sin embargo, TDD es parte de la solución destinada a abordar este problema. No es el único paso que das. Otras cosas que debe hacer es asegurarse de que haya más comentarios de los clientes y con más frecuencia.

Sin embargo, en mi experiencia, TDD es algo muy difícil de implementar con éxito. Es difícil obtener pruebas escritas antes de que haya un producto porque muchas pruebas automatizadas requieren tener algo con lo que jugar para que el software de automatización funcione correctamente. También es difícil lograr que los desarrolladores que no están acostumbrados a las pruebas unitarias lo hagan. Una y otra vez le he dicho a la gente de mi equipo que escriban las pruebas PRIMERO. Nunca he conseguido uno para hacerlo. Al final, las limitaciones de tiempo y la política destruyeron todos los esfuerzos, por lo que ya ni siquiera hacemos pruebas unitarias. Esto, por supuesto, condujo, inevitablemente, a que el diseño se acoplara accidental y severamente, de modo que incluso si quisiéramos, ahora sería prohibitivamente costoso implementarlo. Evitar ESO es lo que TDD finalmente proporciona a los desarrolladores.

Edward extraño
fuente
+1 Gracias por la respuesta integral, Noah. Estoy de acuerdo en que la principal diferencia entre TDD y no TDD es cuando se escriben las pruebas. Sin embargo, también creo que la primera "D" en TDD significa "impulsado", lo que significa que, en TDD, todo el desarrollo está impulsado por las pruebas. Eso es lo que me parece más desconcertante. No tengo problemas para escribir pruebas antes de construir realmente lo que se va a probar. ¿Pero dejar que las pruebas conduzcan? ¿En qué se diferencia eso de una luz verde para hacer algo siempre que lo superficial (es decir, el resultado) esté bien?
CesarGon
Bueno, César, ¿qué propondrías como un criterio mejor y objetivo para decidir cuándo se termina una tarea de desarrollo? Si, como está en TDD, la prueba es la especificación a la que apunta un desarrollador, entonces el desarrollador ha hecho su trabajo cuando la prueba pasa, ¿no? Sí, puede haber fallas en la prueba al igual que puede haber fallas en cualquier especificación. Sin embargo, esa no es la tarea de los desarrolladores por resolver. Si la prueba es defectuosa, entonces se repara, el desarrollo se dirige al nuevo objetivo y, cuando todo está verde, están listos. Funciona porque SIEMPRE hay que pasar una prueba ... sin pelusa extra, indocumentada.
Edward Strange el
3
Tal vez no me expresé claramente. Las pruebas pueden ser una buena manera de determinar cuándo ha terminado. Pero no creo que sean una buena manera de decidir qué debes construir. Y, en TDD, encuentro que las personas están usando pruebas para decidir qué se supone que deben construir. ¿Es esa tu experiencia también?
CesarGon
No. Nuestras construcciones son automatizadas. Se desencadenan por los cambios. Como dije, TDD es solo una parte de la solución.
Edward Strange el
9

Diseño primero

TDD no es una excusa para saltear el diseño. He visto muchos saltar en el tren "ágil" porque pensaron que podrían comenzar a codificar de inmediato. Verdaderamente ágil lo llevará a la codificación de estadísticas mucho más rápido que las buenas prácticas de ingeniería (otro campo) que inspiraron el proceso en cascada.

Pero prueba temprano

Cuando uno dice que la prueba está impulsando el diseño, simplemente significa que puede usar las pruebas muy temprano en la fase de diseño, mucho antes de que se complete. Hacer estas pruebas influirá fuertemente en su diseño al desafiar las áreas grises y enfrentarlo con el mundo real mucho antes de que se complete el producto. obligándote a volver al diseño y ajustarlo para tener esto en cuenta.

Prueba y diseño ... uno y lo mismo

En mi opinión, TDD simplemente hace que la prueba sea una parte integral del diseño en lugar de algo que se hace al final para validarlo. A medida que comienzas a usar TDD, cada vez te pones más en la mentalidad de cómo destruir / romper tu sistema a medida que lo diseñas. Personalmente, no siempre hago mis pruebas primero. Claro que hago las pruebas obvias (unitarias) en una interfaz, pero las ganancias reales provienen de las pruebas de integración y especificación que creo cuando pienso en una forma nueva y creativa que este diseño puede romper. Tan pronto como pienso en una forma, codifico una prueba para ver qué sucede. A veces puedo vivir con la consecuencia, en este caso muevo la prueba en un proyecto separado que no es parte de la compilación principal (ya que continuará fallando).

Entonces, ¿quién conduce el espectáculo?

En TDD, conducir aquí simplemente significa que sus pruebas influyen tan fuertemente en su diseño que uno puede sentir que realmente lo están conduciendo. Sin embargo, uno se detiene en eso, y aquí entiendo sus preocupaciones, da un poco de miedo ... ¿quién conduce el espectáculo?

USTED conduce, no las pruebas. Las pruebas están ahí para que, a medida que avanza, gane un buen nivel de confianza en lo que ha creado, lo que le permite construir más sabiendo que se basa en bases sólidas.

sólido siempre y cuando las pruebas sean sólidas

Exactamente , de ahí el impulsado en el TDD. No es tanto que las pruebas conduzcan todo, sino que tendrán una influencia tan profunda sobre cómo se hacen las cosas, sobre cómo diseñar y pensar su sistema que delegará una gran parte de su proceso de pensamiento a las pruebas y, a cambio Tendrán una profunda influencia en su diseño.

Sí, pero si hago eso con mi puente ...

detente ahí mismo ... la ingeniería de software es MUY diferente de cualquier otra práctica de ingeniería por ahí. De hecho, la ingeniería de software tiene mucho más en común con la literatura. Uno puede tomar un libro terminado, extraer 4 capítulos de él y escribir dos nuevos capítulos para reemplazarlos, pegarlos en el libro y aún tiene un buen libro. Con buenas pruebas y software, puede rasgar cualquier parte de su sistema y reemplazarlo por otro, y el costo de hacerlo no es mucho más alto de lo que lo estaba creando en primer lugar. De hecho, si hiciste tus pruebas y permitiste que influyeran en tu diseño lo suficiente, podría ser más barato que crearlo en primer lugar, ya que tendrás un cierto nivel de confianza de que este reemplazo no romperá lo que cubren las pruebas.

Si es tan bueno, ¿cómo es que no siempre funciona?

Porque las pruebas requieren una mentalidad MUY diferente que la construcción. No todos pueden regresar y volver, de hecho, algunas personas no podrán construir pruebas adecuadas simplemente porque no pueden decidir destruir su creación. Esto generará proyectos con muy pocas pruebas o pruebas lo suficiente como para alcanzar una métrica objetivo (me viene a la mente la cobertura del código). Serán felices las pruebas de ruta y las pruebas de excepción, pero se olvidarán de los casos de esquina y las condiciones de contorno.

Otros solo confiarán en las pruebas para el diseño parcial o total. Cada miembro hace lo suyo y luego se integra entre sí. El diseño es ante todo una herramienta de comunicación, apuestas que establecemos en el suelo para decir que aquí es donde voy a estar, bocetos que dicen que aquí es donde estarán las puertas y las ventanas. Sin esto, su software está condenado independientemente de cuántas pruebas ponga en la cosa. La integración y las fusiones siempre serán dolorosas y les faltarán pruebas en los niveles más altos de abstracciones.

Para estos equipos, TDD puede no ser el camino a seguir.

Newtopian
fuente
7

Con TDD, tiende a no escribir código que no sea fácil o rápido de probar. Esto puede parecer algo pequeño, pero puede tener un profundo efecto en un proyecto ya que afecta lo fácil que es refactorizar, probar, reproducir errores con pruebas y verificar correcciones.

También es más fácil para un nuevo desarrollador en el proyecto ponerse al día cuando tiene un código factorizado mejor respaldado por las pruebas.

Alba
fuente
2
Me gusta esto: enfatiza el punto de que no es tanto el TDD lo que crea los beneficios (aunque tener pruebas unitarias claramente tiene una gran cantidad de valor) como el tipo de código que produce en el sentido de que es comprobable (de forma aislada) y de ahí se desprende todo tipo de cosas buenas (separación de preocupaciones, IoC e inyección de dependencia, etc.)
Murph
1
@Murph, sí, TDD te ayuda a ser honesto :)
Alb
1
Para ser sincero, en realidad no estoy convencido por el argumento "más fácil de poner al día": las pruebas pueden ser útiles, pero el código (en su conjunto, no necesariamente de forma aislada) puede ser algo más difícil de descifrar, ya que algunas cosas serán útiles aparece como por arte de magia, por ejemplo, no sabes qué implementación de IInjectedThing estás usando.
Murph
@Murph La teoría es que la implementación IInjectedThing también está bien diseñada y cubierta por buenas pruebas, por lo que realmente no necesita saber en qué consiste para poder comprender una clase en la que se inyecta.
Adam Lear
@Anna: sí, hasta cierto punto ... si estás tratando de averiguar dónde se rompe algo (siempre siento que la búsqueda de errores es una buena manera de encontrar el equilibrio en un proyecto) o donde algo necesita ser cambiado / Agregó que necesita saber dónde. Incluso si ese lugar está bien encapsulado, aún necesita encontrarlo ... y si eso significa reemplazar algo (nueva implementación de IWhatsit), entonces necesita saber cómo usar la implementación alternativa. Una vez más, no estoy diciendo que la construcción es mala, demasiada evidencia de lo contrario, sino que sugiero que algunas cosas pueden ser menos obvias.
Murph
5

He estado pensando mucho en esto, a pesar de que yo no practico tanto TDD. Parece haber una correlación positiva (¿fuerte?) Entre la calidad del código y el siguiente TDD.

1) Mi primer punto de vista es que, esto no se debe (principalmente) a que TDD agregue "mejor calidad" al código (como tal), es más como que TDD ayuda a eliminar las peores partes y hábitos y, por lo tanto, aumenta indirectamente la calidad.

Incluso recomendaría que no sea la prueba en sí misma, es el proceso de escribir esas pruebas. Es difícil escribir pruebas para un código incorrecto, y viceversa. Y mantener esto en la parte posterior de la cabeza mientras se programa, elimina muchos códigos malos.

2) Otro punto de vista (esto se está volviendo filosófico) es seguir los hábitos mentales del maestro. No aprendes a convertirte en un maestro siguiendo sus "hábitos externos" (por ejemplo, una barba larga es buena), debes aprender sus formas internas de pensar, y esto es difícil. Y de alguna manera los programadores (novatos) siguen TDD, alinean sus formas de pensar más cerca de las de los maestros.

Maglob
fuente
+1 Creo que lo lograste, Maglob. Me gusta especialmente su explicación de que "TDD ayuda a eliminar las peores partes y hábitos, [...] aumentando indirectamente la calidad". Y la analogía de la larga barba también es muy buena.
CesarGon
no escribe pruebas para un código incorrecto, pero escribe una prueba y luego escribe el código para que la prueba pase.
Maglob, por amor al lado más práctico de las cosas, lo tienes mejor cubierto. @ Thorbjørn, creo que Maglob se estaba arrastrando más allá de las líneas que si su diseño proyectado apesta, sus pruebas seguramente tendrán que absorber directamente el nivel de suficiencia que intenta materializar y el olor a podrido debería apestar en sus pruebas antes incluso te pones a escribir cualquier código real.
Filip Dupanović
3

El enfoque de "prueba de escritura + refactorización hasta pasar" parece increíblemente anti-ingeniería.

Parece tener una idea errónea sobre la refactorización y TDD.

La refactorización de código es el proceso de cambiar el código fuente de un programa de computadora sin modificar su comportamiento funcional externo para mejorar algunos de los atributos no funcionales del software.

Por lo tanto, no puede refactorizar el código hasta que pase.

Y TDD, específicamente las pruebas unitarias (que considero la mejora central, ya que otras pruebas me parecen plausibles), no se trata de rediseñar un componente hasta que funcione. Se trata de diseñar un componente y trabajar en la implementación hasta que el componente funcione como se diseñó.

También es importante comprender realmente que las pruebas unitarias se tratan de probar unidades . Debido a la tendencia a escribir siempre muchas cosas desde cero, es importante probar tales unidades. Un ingeniero civil ya conoce las especificaciones de las unidades que usa (los diferentes materiales) y puede esperar que funcionen. Estas son dos cosas que a menudo no se aplican a los ingenieros de software, y es muy profesional para probar las unidades antes de usarlas, porque significa usar componentes probados y de alta calidad.
Si un ingeniero civil tuvo la idea de usar un nuevo tejido de fibra para hacer un techo para cubrir un estadio, esperaría que lo pruebe como una unidad, es decir, defina las especificaciones necesarias (por ejemplo, peso, permeabilidad, estabilidad, etc.) y luego pruebe y refínelo hasta que los encuentre.

Por eso funciona TDD. Porque si crea software de unidades probadas, es mucho mejor que funcione, cuando las conecta y si no es así, puede esperar que el problema esté en su código de pegamento, suponiendo que sus pruebas tengan una buena cobertura.

editar:
Refactorización significa: sin cambios en la funcionalidad. Un punto de la prueba de la unidad de escritura es asegurarse de que la refactorización no rompa el código. Entonces, TDD tiene la intención de asegurar que la refactorización no tenga efectos secundarios.
La granularidad no es un tema de perspectiva, porque como dije, la unidad prueba las unidades de prueba y no los sistemas, por lo que la granularidad se define exactamente.

TDD fomenta la buena arquitectura. Requiere que defina e implemente especificaciones para todas sus unidades, lo que le obliga a diseñarlas antes de la implementación, lo cual es todo lo contrario de lo que parece pensar. TDD dicta la creación de unidades, que se pueden probar individualmente y, por lo tanto, se desacoplan por completo.
TDD no significa que arroje una prueba de software al código de espagueti y revuelva la pasta hasta que pase.

En contraposición a la ingeniería civil, en ingeniería de software un proyecto generalmente evoluciona constantemente. En ingeniería civil, tiene el requisito de construir un puente en la posición A, que pueda transportar x toneladas y sea lo suficientemente ancho para n vehículos por hora.
En ingeniería de software, el cliente básicamente puede decidir en cualquier momento (posiblemente después de la finalización), quiere un puente de dos pisos, y quiere que esté conectado con la autopista más cercana, y que le gustaría que fuera un puente de elevación, porque su compañía Recientemente comenzó a utilizar veleros.
Los ingenieros de software tienen la tarea de cambiar los diseños. No porque sus diseños sean defectuosos, sino porque ese es el modus operandi. Si el software está bien diseñado, se puede rediseñar a alto nivel, sin tener que reescribir todos los componentes de bajo nivel.

TDD se trata de construir software con componentes altamente desacoplados y probados individualmente. Bien ejecutado, lo ayudará a responder a los cambios en los requisitos significativamente más rápido y seguro que sin él.

TDD agrega requisitos al proceso de desarrollo, pero no prohíbe ningún otro método de garantía de calidad. Por supuesto, TDD no proporciona la misma seguridad que la verificación formal, pero, una vez más, la verificación formal es extremadamente costosa e imposible de usar a nivel de sistema. Y aún así, si quisieras, podrías combinar ambos.

TDD también abarca pruebas distintas de las pruebas unitarias, que se realizan a nivel de sistema. Encuentro esto fácil de explicar pero difícil de ejecutar y difícil de medir. Además, son bastante plausibles. Si bien veo absolutamente su necesidad, realmente no los valoro como ideas.

Al final, ninguna herramienta realmente resuelve un problema. Las herramientas solo facilitan la resolución de un problema. Puedes preguntar: ¿Cómo me ayudará un cincel con una gran arquitectura? Bueno, si planeas hacer paredes rectas, los ladrillos rectos son de ayuda. Y sí, claro, si le das esa herramienta a un idiota, probablemente la golpeará con el pie eventualmente, pero eso no es culpa del cincel, por mucho que no sea un defecto de TDD que da falsa seguridad a los novatos, quienes no escriben buenas pruebas.
Entonces, en el fondo, uno puede decir que TDD funciona mucho mejor que ningún TDD.

back2dos
fuente
No creo tener una idea equivocada; Estoy de acuerdo con la definición de refactorización de código que ha publicado, pero también creo que debe tener en cuenta la granularidad de los cambios en el código. Cuando dice "el proceso de cambiar el código fuente de un programa de computadora", debe darse cuenta de que, desde la perspectiva de un determinado conjunto, el comportamiento no cambia, pero el comportamiento de las partes sí cambia. Así es como se efectúa el cambio. Además de esto, te escucho sobre por qué funciona TDD (y lo comparto), pero ¿cómo se aborda la arquitectura según mi publicación original?
CesarGon
@CesarGon: Publicación actualizada.
back2dos
2

No me gusta que digas 'la prueba, en lugar del usuario, establece el requisito'. Creo que solo está considerando las pruebas unitarias en TDD, mientras que también cubre las pruebas de integración.

Además de probar las bibliotecas que constituyen la base del software, escriba las pruebas que cubren las interacciones que sus usuarios tienen con el software / sitio web / lo que sea. Estos provienen directamente de los usuarios, y las bibliotecas como pepino (http://cukes.info) pueden incluso permitir que sus usuarios escriban las pruebas ellos mismos, en lenguaje natural.

TDD también fomenta la flexibilidad en el código: si pasas una eternidad diseñando la arquitectura de algo, será increíblemente difícil hacer esos cambios más adelante si es necesario. Comience escribiendo un par de pruebas, luego escriba un pequeño código que pase esas pruebas. Agregue más pruebas, agregue más código. Si necesita cambiar radicalmente el código, sus pruebas aún se mantienen.

Y a diferencia de los puentes y los automóviles, una sola pieza de software puede sufrir grandes cambios a lo largo de su vida útil, y realizar una refactorización compleja sin tener que escribir primero las pruebas es solo una cuestión de problemas.

sevenseacat
fuente
Te escucho sobre los beneficios que reclamas para TDD. Pero por lo que yo entiendo, no abordas los problemas de arquitectura y calidad de prueba que pido explícitamente en mi pregunta.
CesarGon
@CesarGon: Creo que sus preguntas específicas se aplican a cualquier tipo de prueba, no solo a TDD. Así que me concentré en las características específicas de TDD que 'funcionan'.
sevenseacat
1
Las pruebas de integración definitivamente tienen más sentido que las pruebas unitarias independientes. La mayoría de los casos de errores con los que tropiezo nunca habrían sido encontrados por pruebas unitarias, solo por probar todo el sistema real con todos sus pernos y silbatos en su lugar.
2

Creo que te estás acercando al primer punto desde el ángulo equivocado.

Desde un punto de vista teórico, estamos demostrando que algo funciona comprobando los puntos de falla. Ese es el método utilizado. Puede haber muchas otras formas en que puede probar que algo es funcional, pero TDD se ha establecido debido a la simplicidad de su enfoque basado en bits: si no se rompe, funciona.

En la práctica, esto se traduce abiertamente en: ahora podemos pasar al siguiente paso (después de haber aplicado TDD con éxito para satisfacer todos los predicados). Si te acercas a TDD desde esta perspectiva, entonces no se trata de "escribir pruebas + refactorizar hasta pasar", sino más bien de haber completado esto, ahora me estoy enfocando completamente en la siguiente característica como lo más importante .

Piense cómo se aplica esto a la ingeniería civil. Estamos construyendo un estadio que puede albergar una audiencia pública de 150000 personas. Después de demostrar que la integridad estructural del estadio es sólida, primero hemos satisfecho la seguridad . Ahora podemos centrarnos en otros temas que se vuelven inmediatamente importantes, como baños, puestos de comida, asientos, etc., haciendo que la experiencia de la audiencia sea más placentera. Esto es una simplificación excesiva, ya que hay mucho más para TDD, pero el quid es que no obtienes la mejor experiencia de usuario posible si te enfocas en características nuevas y emocionantes y mantienes la integridad al mismo tiempo. Lo obtienes a mitad de camino en ambos casos. Quiero decir, ¿cómo puedes saber exactamente cómoCuántos baños y dónde colocar para 150000 personas? Raramente he visto colapsar estadios en mi propia vida, pero he tenido que esperar en la fila durante el medio tiempo en muchas ocasiones. Eso dice que el problema del baño es posiblemente más complejo y si los ingenieros pueden dedicar menos tiempo a la seguridad, finalmente podrán resolver el problema del baño.

Su segundo punto es irrelevante, porque ya hemos acordado que los absolutos son un esfuerzo tonto y porque Hank Moody dice que no existen (pero parece que no puedo encontrar una referencia para eso).

Filip Dupanović
fuente
+1 para una buena explicación de mi primer punto, y para la referencia a Hank Moody. Glorioso.
CesarGon
2
Gracias lo aprecio. Veo TDD más como un fenómeno psicológico, en lugar de un enfoque / proceso técnico. Pero esa es solo mi visión del mundo al respecto.
Filip Dupanović
¿Puedes saber exactamente cuántos lavabos y dónde deben colocarse? La respuesta es sí: pregúntele a cualquier arquitecto y le dirán que esta información se realiza por adelantado y, a veces, con datos estadísticos claros para respaldarla.
gbjbaanb
1

TDD en ingeniería de software es una buena práctica, de la misma manera que el manejo de errores en las aplicaciones es una buena práctica, así como el registro y el diagnóstico (aunque es parte del manejo de errores).

TDD no debe usarse como una herramienta para reducir el desarrollo de software en codificación de prueba y error. Pero aún así, la mayoría de los programadores observan los registros de tiempo de ejecución, observan excepciones en el depurador o usan otros signos de falla / éxito durante su fase de desarrollo que consiste en codificar / compilar / ejecutar la aplicación, todo el día.

TDD es solo una forma de formalizar y automatizar esos pasos para que usted como desarrollador sea más productivo.

1) No se puede comparar la ingeniería de software con la construcción de puentes, la flexibilidad en la construcción de puentes no se acerca a la de diseñar un programa de software. Construir el puente es como escribir el mismo programa una y otra vez en una máquina con pérdidas. Los puentes no se pueden duplicar y reutilizar como el software sí. Cada puente es único y tiene que ser fabricado. Lo mismo ocurre con los automóviles y otros diseños.

Lo más difícil en la ingeniería de software es reproducir fallas, cuando un puente falla generalmente es muy fácil determinar qué salió mal y, en teoría, es fácil reproducir la falla. Cuando un programa de computadora falla, puede ser una cadena compleja de eventos que llevó al sistema a un estado defectuoso y puede ser muy difícil determinar dónde está el error. La prueba de unidad y TDD facilita la prueba de la solidez de los componentes de software, bibliotecas y algoritmos.

2) Usar pruebas de unidades débiles y casos de prueba poco profundos que no estresen al sistema para generar un falso sentido de confianza es solo una mala práctica. Ignorar la calidad arquitectónica de un sistema y simplemente cumplir con las pruebas es, por supuesto, tan malo. Pero engañar en el lugar de construcción para un rascacielos o un puente para guardar material y no seguir los planos es tan malo y sucede todo el tiempo ...

Ernelli
fuente
No estoy de acuerdo con su implicación de que es fácil en los sistemas físicos (es decir, no software) reproducir fallas. Observe el trabajo extremadamente complejo y arduo que es necesario para determinar las causas fundamentales de fallas mecánicas en accidentes de tránsito aéreo, por ejemplo.
CesarGon
Hm, ahora estás comparando un avión que se estrella con un puente que falla, un puente generalmente no puede volar, caso cerrado. Pero la comparación entre aviones y software a veces es válida. Ambas áreas son muy complejas y requieren una metodología de prueba estructurada. Entonces, cuando un puente falla, sabes que se ha sobrecargado. Cuando un avión se estrella, sabes que el estado anormal de volar por encima del suelo falló, pero la razón por lo general requiere una investigación exhaustiva, lo mismo con la falla del software.
Ernelli
Los puentes se pueden duplicar, o al menos, el modelo de puente que le compra al arquitecto puede, aproximadamente, con modificaciones para adaptarse a sus circunstancias exactas. El punto es que si necesita un puente, irá al arquitecto y él le dará una lista de solo unos pocos tipos que puede tener: suspensión, caja, arco, etc., y una lista limitada de materiales para construirlo.
gbjbaanb
1

Si acepta que cuanto antes se encuentren los errores, menor será el costo de corregirlos, entonces eso solo hace que TDD valga la pena.

SnoopDougieDoug
fuente
1
¿Tiene alguna evidencia de que los errores se encuentran antes en un entorno TDD? Además, ¿qué pasa con los efectos secundarios de TDD, como el impacto en la arquitectura?
CesarGon
0

TDD no se trata realmente de pruebas. Y ciertamente no es un reemplazo para una buena prueba. Lo que le ofrece es un diseño bien pensado, fácil de consumir para el consumidor y fácil de mantener y refactorizar más tarde. Esas cosas a su vez conducen a menos errores y un diseño de software mejor y más adaptable. TDD también lo ayuda a pensar y documentar sus suposiciones, a menudo descubriendo que algunas de ellas eran incorrectas. Lo descubres muy temprano en el proceso.

Y como un buen beneficio adicional, tiene un gran conjunto de pruebas que puede ejecutar para asegurarse de que una refactorización no cambie el comportamiento (entradas y salidas) de su software.

Marcie
fuente
66
-1. Mucha gente sigue diciendo esto, pero aún no he visto la magia que lo hace posible.
Bart van Ingen Schenau
@Bart van Ingen Schenau, ¿has hecho TDD? Lo he estado haciendo durante aproximadamente 4 años, y definitivamente he visto suceder la "magia".
Marcie
0

Te daré una respuesta corta. Por lo general, TDD se ve de la manera incorrecta al igual que las pruebas unitarias. Nunca entendí las pruebas unitarias hasta hace poco después de ver un buen video de tecnología. Esencialmente, TDD solo indica que desea que las siguientes cosas funcionen. DEBEN ser implementados. Luego diseñas el resto del software de la manera que lo harías normalmente.

Es como escribir casos de uso para una biblioteca antes de diseñarla. Excepto que puede cambiar el caso de uso en una biblioteca y es posible que no lo haga para TDD (uso TDD para el diseño de API). También se le recomienda agregar más pruebas y pensar en entradas / usos salvajes que la prueba puede obtener. Me resulta útil al escribir bibliotecas o API donde, si cambia algo, debe saber que rompió algo. En la mayoría del software del día a día no me molesto, ya que ¿por qué necesito un caso de prueba para un usuario que presiona un botón o si quiero aceptar una lista CSV o una lista con una entrada por línea ... Eso realmente no importa? para cambiarlo así no debería / no puedo usar TDD.


fuente
0

El software es orgánico, cuando la ingeniería estructural es concreta.

Cuando construyas tu puente, seguirá siendo un puente y es poco probable que evolucione a otra cosa en un corto período de tiempo. Se realizarán mejoras durante meses y años, pero no horas y días como en el software.

Cuando prueba de forma aislada, normalmente hay dos tipos de marcos que puede usar. Marco restringido y sin restricciones. Los marcos sin restricciones (en .NET) le permiten probar y sustituir todo, independientemente de los modificadores de acceso. Es decir, puede tropezar y burlarse de componentes privados y protegidos.

La mayoría de los proyectos que he visto utilizan marcos restringidos (RhinoMocks, NSubstitute, Moq). Cuando pruebe con estos marcos, debe diseñar su aplicación de tal manera que pueda inyectar y sustituir dependencias en tiempo de ejecución. Esto implica que debe tener un diseño ligeramente acoplado. El diseño ligeramente acoplado (cuando se hace correctamente) implica una mejor separación de las preocupaciones, lo cual es algo bueno.

Para resumir, creo que pensar detrás de esto es que si su diseño es comprobable, por lo tanto, está acoplado libremente y tiene una buena separación de preocupaciones.

En una nota al margen, he visto aplicaciones que eran realmente comprobables, pero mal escritas desde la perspectiva del diseño orientado a objetos.

CodeART
fuente
0

¿Por qué funciona TDD?

No lo hace.

Aclaración: las pruebas automatizadas son mejores que ninguna prueba. Sin embargo, personalmente creo que la mayoría de las pruebas unitarias son un desperdicio porque generalmente son tautológicas (es decir, dicen cosas obvias del código real bajo prueba) y no se puede probar fácilmente que sean consistentes, no redundantes y cubran todos los casos límite (donde generalmente ocurren errores )

Y lo más importante: el buen diseño de software no se cae mágicamente de las pruebas, como lo anuncian muchos evangelistas ágiles / TDD. Todos los que afirmen lo contrario deben proporcionar enlaces a investigaciones científicas revisadas por pares que prueben esto, o al menos una referencia a algún proyecto de código abierto donde los beneficios de TDD puedan ser potencialmente estudiados por su historial de cambios de código.

Kola
fuente