¿Cómo se realiza la prueba unitaria de una prueba unitaria? [cerrado]

89

Estaba viendo los webcasts de Rob Connerys en la aplicación MVCStoreFront y me di cuenta de que estaba probando unitariamente incluso las cosas más mundanas, cosas como:

public Decimal DiscountPrice
{
   get
   {
       return this.Price - this.Discount;
   }
}

Tendría una prueba como:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,80);
}

Si bien estoy a favor de las pruebas unitarias, a veces me pregunto si esta forma de desarrollo de la primera prueba es realmente beneficiosa, por ejemplo, en un proceso real, tiene 3-4 capas por encima de su código (Solicitud comercial, Documento de requisitos, Documento de arquitectura) , donde la regla comercial definida real (Precio de descuento es Precio - Descuento) podría estar mal definida.

Si esa es la situación, su prueba unitaria no significa nada para usted.

Además, su prueba unitaria es otro punto de falla:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,90);
}

Ahora la prueba tiene fallas. Obviamente, en una prueba simple, no es gran cosa, pero digamos que estábamos probando una regla comercial complicada. ¿Qué ganamos aquí?

Avance rápido dos años en la vida de la aplicación, cuando los desarrolladores de mantenimiento la mantienen. Ahora que la empresa cambia su regla y la prueba se rompe de nuevo, un desarrollador novato corrige la prueba incorrectamente ... ahora tenemos otro punto de falla.

Todo lo que veo son más posibles puntos de falla, sin un rendimiento beneficioso real, si el precio de descuento es incorrecto, el equipo de prueba aún encontrará el problema, ¿cómo las pruebas unitarias ahorraron trabajo?

¿Que me estoy perdiendo aqui? Por favor, enséñeme a amar TDD, ya que me está costando aceptarlo como útil hasta ahora. Yo también quiero, porque quiero ser progresista, pero no tiene sentido para mí.

EDITAR: Un par de personas siguen mencionando que las pruebas ayudan a hacer cumplir la especificación. En mi experiencia, la especificación también ha sido incorrecta, la mayoría de las veces, pero tal vez estoy condenado a trabajar en una organización donde las especificaciones están escritas por personas que no deberían escribir especificaciones.

FlySwat
fuente
5
en muchos casos, la prueba unitaria es la especificación, ¡y la documentación también!
Steven A. Lowe
32
... y luego prueba unitaria la prueba unitaria de la prueba unitaria ... pero ¿qué pasa con la prueba unitaria ^ 4 y la prueba unitaria ^ 5 ... aaaaaaaaahhhhhhhhh!
dacracot
14
Ninguna cantidad de ningún tipo de prueba le salvará de una especificación incorrecta.
Bill the Lizard
4
¿Alguien más acaba de escuchar lo que sonó como una mano aplaudiendo?
gnovice
9
Creo que la cita apropiada es "Son solo tortugas hasta el final".
Quinn Taylor

Respuestas:

63

Primero, las pruebas son como la seguridad: nunca puedes estar 100% seguro de que lo tienes, pero cada capa agrega más confianza y un marco para solucionar más fácilmente los problemas que quedan.

En segundo lugar, puede dividir las pruebas en subrutinas que luego se pueden probar. Cuando tiene 20 pruebas similares, hacer una subrutina (probada) significa que su prueba principal son 20 invocaciones simples de la subrutina, que es mucho más probable que sea correcta.

En tercer lugar, algunos argumentarían que TDD aborda esta preocupación. Es decir, si solo escribe 20 pruebas y pasan, no está completamente seguro de que realmente estén probando algo. Pero si cada prueba que escribió inicialmente falló y luego la solucionó, entonces estará mucho más seguro de que realmente está probando su código. En mi humilde opinión, este ida y vuelta lleva más tiempo del que vale, pero es un proceso que trata de abordar su preocupación.

Jason Cohen
fuente
2
Para jugar al defensor del diablo, veo capas adicionales como más posibles puntos de falla, eso no aumenta la confianza para mí. En mi trabajo real, trabajo con muchos equipos en una empresa SOA altamente distribuida. Cada uno de esos equipos podría poner en peligro el proyecto si su capa falla.
FlySwat
2
Es por eso que está utilizando objetos simulados para probar cada capa por separado.
Toon Krijthe
10
Genial, entonces mi prueba pasará usando IMockedComplexObject pero cuando realmente uso un ComplexObject en el mundo real, falla ... No he ganado nada nuevamente.
FlySwat
16
@Jonathan: no, ha ganado la confianza de que su código funciona, asumiendo que desarrolló la interfaz de ComplexObject y lo probó adecuadamente con esa interfaz. En el peor de los casos, ha adquirido el conocimiento de que su comprensión de ComplexObject no fue lo que esperaba.
tvanfosson
9
@FlySwat: En respuesta a su comentario sobre IMockedComplexObject, cito el comentario de Cwash sobre otra respuesta: "No te burlas de lo que estás tratando de probar, te burlas de lo que no estás tratando de probar".
Brian
39

Es poco probable que una prueba incorrecta rompa su código de producción. Al menos, no es peor que no tener ninguna prueba. Por lo tanto, no es un "punto de falla": las pruebas no tienen que ser correctas para que el producto realmente funcione. Es posible que tengan que ser correctos antes de que se firme como que funciona, pero el proceso de corregir las pruebas rotas no pone en peligro su código de implementación.

Puede pensar en las pruebas, incluso las pruebas triviales como estas, como una segunda opinión de lo que se supone que debe hacer el código. Una opinión es la prueba, la otra es la implementación. Si no están de acuerdo, entonces sabes que tienes un problema y miras más de cerca.

También es útil si alguien en el futuro quiere implementar la misma interfaz desde cero. No deberían tener que leer la primera implementación para saber qué significa Descuento, y las pruebas actúan como una copia de seguridad inequívoca de cualquier descripción escrita de la interfaz que pueda tener.

Dicho esto, estás intercambiando tiempo. Si hay otras pruebas que podría estar escribiendo utilizando el tiempo que ahorra omitiendo estas pruebas triviales, tal vez sean más valiosas. Depende de la configuración de prueba y de la naturaleza de la aplicación, en realidad. Si el descuento es importante para la aplicación, de todos modos detectará cualquier error en este método en las pruebas funcionales. Todo lo que hace la prueba de unidad es permitirle detectarlos en el punto en que está probando esta unidad, cuando la ubicación del error será inmediatamente obvia, en lugar de esperar hasta que la aplicación se integre y la ubicación del error pueda ser menos obvia.

Por cierto, personalmente no usaría 100 como precio en el caso de prueba (o más bien, si lo hiciera, agregaría otra prueba con otro precio). La razón es que alguien en el futuro podría pensar que se supone que el descuento es un porcentaje. Uno de los propósitos de las pruebas triviales como esta es garantizar que se corrijan los errores al leer la especificación.

[Con respecto a la edición: creo que es inevitable que una especificación incorrecta sea un punto de falla. Si no sabe lo que se supone que debe hacer la aplicación, es probable que no lo haga. Pero escribir pruebas para reflejar la especificación no magnifica este problema, simplemente no lo resuelve. Por lo tanto, no está agregando nuevos puntos de falla, solo está representando las fallas existentes en el código en lugar de la documentación de waffle .]

Steve Jessop
fuente
4
Una prueba incorrecta permitirá que el código roto entre en libertad. Ahí es donde se introduce la falla. Proporciona una falsa sensación de confianza.
FlySwat
9
Eso es cierto, pero no tener ninguna prueba también permite que salga código roto. El error es pensar que si el código pasa las pruebas unitarias, debe ser correcto; eso me curó bastante temprano en mi carrera. Por lo tanto, una prueba unitaria rota no deja que el código roto salga a la luz, solo lo deja pasar a las pruebas de integración.
Steve Jessop
7
Además, incluso una prueba incorrecta puede detectar un código roto, siempre que contenga errores diferentes de la implementación. Ese es mi punto de que las pruebas no tienen que ser absolutamente correctas, están ahí para llamar su atención sobre áreas de preocupación.
Steve Jessop
2
respuesta muy interesante.
Peter
22

Todo lo que veo son más posibles puntos de falla, sin un rendimiento beneficioso real, si el precio de descuento es incorrecto, el equipo de prueba aún encontrará el problema, ¿cómo las pruebas unitarias ahorraron trabajo?

Realmente no se supone que las pruebas unitarias ahorren trabajo, sino que lo ayudarán a encontrar y prevenir errores. Es más trabajo, pero es el tipo de trabajo correcto. Es pensar en su código en los niveles más bajos de granularidad y escribir casos de prueba que demuestren que funciona en las condiciones esperadas , para un conjunto dado de entradas. Se trata de aislar variables para que pueda ahorrar tiempo buscando en el lugar correcto cuando se presenta un error. Es guardar ese conjunto de pruebas para que pueda usarlas una y otra vez cuando tenga que hacer un cambio en el futuro.

Personalmente, creo que la mayoría de las metodologías no se eliminan muchos pasos de la ingeniería de software del culto de carga , incluido el TDD, pero no es necesario cumplir con el TDD estricto para aprovechar los beneficios de las pruebas unitarias. Conserve las partes buenas y tire las partes que rindan poco beneficio.

Finalmente, la respuesta a su pregunta principal " ¿Cómo se prueba una unidad de prueba? " Es que no debería tener que hacerlo. Cada prueba unitaria debe ser muy simple. Llame a un método con una entrada específica y compárelo con su resultado esperado. Si la especificación de un método cambia, puede esperar que algunas de las pruebas unitarias para ese método también tengan que cambiar. Esa es una de las razones por las que realiza pruebas unitarias con un nivel de granularidad tan bajo, por lo que solo algunas de las pruebas unitarias tienen que cambiar. Si encuentra que las pruebas para muchos métodos diferentes están cambiando para un cambio en un requisito, es posible que no esté probando con un nivel de granularidad lo suficientemente fino.

Bill el lagarto
fuente
"Llame a un método con una entrada específica y compárelo con su resultado esperado". pero ¿qué pasa si el resultado es un tipo complejo ... como un documento XML? No puede simplemente "==", tendrá que escribir un código específico para comparar, y entonces tal vez su método de comparación podría tener errores.
Andy
@andy: Tienes que probar tu método de comparación por separado. Una vez que lo haya probado a fondo, puede confiar en que funcionará en otras pruebas.
Bill the Lizard
genial, gracias Bill. Empecé a trabajar en un lugar nuevo y es la primera vez que hago pruebas unitarias. Creo que, en principio, funciona, y estamos usando Cruise Control donde es realmente útil, pero grandes conjuntos de pruebas parecen sufrir el mismo destino que el código heredado ... simplemente no estoy seguro de eso ...
Andy
11

Las pruebas unitarias están ahí para que sus unidades (métodos) hagan lo que espera. Escribir la prueba primero te obliga a pensar en lo que esperas antes de escribir el código. Pensar antes de hacer siempre es una buena idea.

Las pruebas unitarias deben reflejar las reglas comerciales. Por supuesto, puede haber errores en el código, pero escribir la prueba primero le permite escribirla desde la perspectiva de la regla comercial antes de que se haya escrito cualquier código. Escribir la prueba después, creo, es más probable que conduzca al error que describe porque sabe cómo lo implementa el código y se siente tentado a asegurarse de que la implementación sea correcta, no de que la intención sea correcta.

Además, las pruebas unitarias son solo una forma, y ​​la más baja, de las pruebas que debería estar escribiendo. También deben redactarse pruebas de integración y pruebas de aceptación, estas últimas por parte del cliente, si es posible, para asegurarse de que el sistema funciona de la manera esperada. Si encuentra errores durante esta prueba, vuelva atrás y escriba pruebas unitarias (que fallan) para probar el cambio en la funcionalidad para que funcione correctamente, luego cambie su código para que la prueba pase. Ahora tiene pruebas de regresión que capturan las correcciones de errores.

[EDITAR]

Otra cosa que he encontrado con TDD. Casi obliga a un buen diseño por defecto. Esto se debe a que los diseños altamente acoplados son casi imposibles de realizar pruebas unitarias de forma aislada. No lleva mucho tiempo usar TDD para darse cuenta de que el uso de interfaces, la inversión de control y la inyección de dependencias, todos los patrones que mejorarán su diseño y reducirán el acoplamiento, son realmente importantes para el código comprobable.

tvanfosson
fuente
Quizás aquí es donde radica mi problema. Puedo visualizar el algoritmo de una regla de negocio con más facilidad de lo que puedo visualizar el resultado, por lo que no tengo problemas para implementar el código en sí, pero veo que burlarse de la regla es redundante. Tal vez sea así como pienso.
FlySwat
Eso es exactamente lo que haces en una prueba unitaria. Divida ese algoritmo en pedazos y verifique cada pieza. Por lo general, encuentro que mi código se escribe solo porque ya escribí la expectativa en mi prueba unitaria.
tvanfosson
Mock es un término sobrecargado en el espacio de prueba. No se burla de lo que está tratando de probar, se burla de lo que no está tratando de probar ... Cuando escribe la prueba para su regla comercial, crea un código que lo invoca, no se burla en absoluto .
cwash
@cwash: no estoy seguro de cómo se aplica su comentario a mi respuesta. No mencioné burlarse ... y estoy de acuerdo con tu observación.
tvanfosson
@tvanfosson - mi último comentario fue en respuesta a @FlySwat "... burlándose de la regla como redundante". Lo siento, olvidé especificar.
cwash
10

¿Cómo se prueba una prueba ? La prueba de mutación es una técnica valiosa que personalmente he utilizado con resultados sorprendentemente buenos. Lea el artículo vinculado para obtener más detalles y vínculos a aún más referencias académicas, pero en general "prueba sus pruebas" modificando su código fuente (cambiando "x + = 1" a "x - = 1" por ejemplo) y luego volver a ejecutar sus pruebas, asegurándose de que al menos una prueba falle. Cualquier mutación que no cause fallas en las pruebas se marca para una investigación posterior.

Se sorprendería de cómo puede tener una cobertura del 100% de líneas y sucursales con un conjunto de pruebas que parecen completas y, sin embargo, puede cambiar fundamentalmente o incluso comentar una línea en su fuente sin que ninguna de las pruebas se queje. A menudo, esto se reduce a no probar con las entradas correctas para cubrir todos los casos de límites, a veces es más sutil, pero en todos los casos me impresionó la cantidad de resultados que obtuve.

Andrzej Doyle
fuente
1
+1 concepto interesante del que aún no había oído hablar
Wim Coenen
9

Cuando se aplica el desarrollo basado en pruebas (TDD), se comienza con una prueba fallida . Este paso, que puede parecer innecesario, en realidad está aquí para verificar que la prueba unitaria está probando algo. De hecho, si la prueba nunca falla, no aporta ningún valor y, lo que es peor, conduce a una confianza incorrecta, ya que confiará en un resultado positivo que no prueba nada.

Al seguir este proceso estrictamente, todas las "unidades" están protegidas por la red de seguridad que están creando las pruebas unitarias, incluso las más mundanas.

Assert.IsEqual(p.DiscountPrice,90);

No hay ninguna razón por la que la prueba evolucione en esa dirección, o me falta algo en su razonamiento. Cuando el precio es 100 y el descuento 20, el precio con descuento es 80. Esto es como un invariante.

Ahora imagine que su software necesita admitir otro tipo de descuento basado en el porcentaje, tal vez dependiendo del volumen comprado, su método Product :: DiscountPrice () puede volverse más complicado. Y es posible que la introducción de esos cambios rompa la simple regla de descuento que teníamos inicialmente. Luego verá el valor de esta prueba que detectará la regresión de inmediato.


Red - Green - Refactor: esto es para recordar la esencia del proceso TDD.

El rojo se refiere a la barra roja de JUnit cuando falla una prueba.

El verde es el color de la barra de progreso de JUnit cuando pasan todas las pruebas.

Refactorización en condiciones verdes: elimine cualquier duplicación, mejore la legibilidad.


Ahora, para abordar su punto sobre las "3-4 capas por encima del código", esto es cierto en un proceso tradicional (similar a una cascada), no cuando el proceso de desarrollo es ágil. Y ágil es el mundo de donde viene TDD; TDD es la piedra angular de eXtreme Programming .

Agile se trata de comunicación directa en lugar de documentos de requisitos que se tiran por encima de la pared.

filántropo
fuente
8

Si bien estoy a favor de las pruebas unitarias, a veces me pregunto si esta forma de desarrollo de la primera prueba es realmente beneficiosa ...

Pruebas pequeñas y triviales como esta pueden ser el "canario en la mina de carbón" para su código base, alertando del peligro antes de que sea demasiado tarde. Es útil mantener las pruebas triviales porque te ayudan a lograr las interacciones correctas.

Por ejemplo, piense en una prueba trivial implementada para investigar cómo usar una API con la que no está familiarizado. Si esa prueba tiene alguna relevancia para lo que estás haciendo en el código que usa la API "de verdad", es útil mantener esa prueba. Cuando la API lanza una nueva versión y necesita actualizar. Ahora tiene sus suposiciones sobre cómo espera que se comporte la API registradas en un formato ejecutable que puede usar para detectar regresiones.

... [En] un proceso real, tiene 3-4 capas por encima de su código (Solicitud comercial, Documento de requisitos, Documento de arquitectura), donde la regla comercial definida real (Precio de descuento es Precio - Descuento) podría estar mal definida. Si esa es la situación, su prueba unitaria no significa nada para usted.

Si ha estado codificando durante años sin escribir pruebas, es posible que no le resulte obvio de inmediato que tiene algún valor. Pero si tiene la mentalidad de que la mejor manera de trabajar es "lanzar temprano, lanzar con frecuencia" o "ágil" en el sentido de que desea la capacidad de implementar de forma rápida / continua, entonces su prueba definitivamente significa algo. La única forma de hacerlo es legitimando cada cambio que realice en el código con una prueba. No importa cuán pequeña sea la prueba, una vez que tenga un conjunto de pruebas ecológico, en teoría, podrá implementarlo. Consulte también "producción continua" y "beta perpetua".

No tiene que ser "primero la prueba" para tener esta mentalidad, pero esa es generalmente la forma más eficiente de llegar allí. Cuando haces TDD, te encierras en un pequeño ciclo de refactorización rojo verde de dos a tres minutos. En ningún momento no podrá detenerse e irse y tener un lío completo en sus manos que llevará una hora depurar y volver a armar.

Además, su prueba unitaria es otro punto de falla ...

Una prueba exitosa es aquella que demuestra una falla en el sistema. Una prueba fallida le alertará sobre un error en la lógica de la prueba o en la lógica de su sistema. El objetivo de sus pruebas es descifrar su código o demostrar que un escenario funciona.

Si está escribiendo pruebas después del código, corre el riesgo de escribir una prueba que sea "mala" porque para ver que su prueba realmente funciona, necesita verla rota y funcionando. Cuando estás escribiendo pruebas después del código, esto significa que tienes que "lanzar la trampa" e introducir un error en el código para que la prueba falle. La mayoría de los desarrolladores no solo están inquietos por esto, sino que dirían que es una pérdida de tiempo.

¿Qué ganamos aquí?

Definitivamente hay un beneficio en hacer las cosas de esta manera. Michael Feathers define "código heredado" como "código no probado". Cuando adoptas este enfoque, legitimas cada cambio que realizas en tu base de código. Es más riguroso que no usar pruebas, pero cuando se trata de mantener una base de código grande, se paga solo.

Hablando de plumas, hay dos excelentes recursos que debe consultar con respecto a esto:

Ambos explican cómo trabajar este tipo de prácticas y disciplinas en proyectos que no son "Greenfield". Proporcionan técnicas para escribir pruebas en torno a componentes estrechamente acoplados, dependencias cableadas y cosas sobre las que no necesariamente tiene control. Se trata de encontrar "costuras" y probarlas.

[Si] si el precio de descuento es incorrecto, el equipo de prueba aún encontrará el problema, ¿cómo las pruebas unitarias ahorraron trabajo?

Hábitos como estos son como una inversión. Las devoluciones no son inmediatas; se acumulan con el tiempo. La alternativa a no probar es esencialmente asumir la deuda de no poder detectar regresiones, introducir código sin temor a errores de integración o impulsar decisiones de diseño. La belleza es que legitimas cada cambio introducido en tu código base.

¿Que me estoy perdiendo aqui? Por favor, enséñeme a amar TDD, ya que me está costando aceptarlo como útil hasta ahora. Yo también quiero, porque quiero ser progresista, pero no tiene sentido para mí.

Lo veo como una responsabilidad profesional. Es un ideal por el que luchar. Pero es muy difícil de seguir y tedioso. Si le importa y siente que no debe producir código que no esté probado, podrá encontrar la fuerza de voluntad para aprender buenos hábitos de prueba. Una cosa que hago mucho ahora (al igual que otros) es marcarme una hora para escribir código sin ninguna prueba, y luego tener la disciplina para tirarlo a la basura. Esto puede parecer un desperdicio, pero en realidad no lo es. No es que el ejercicio le cueste materiales físicos a una empresa. Me ayudó a comprender el problema y cómo escribir código de tal manera que sea de mayor calidad y comprobable.

Mi consejo sería en última instancia que si realmente no tienes el deseo de ser bueno en eso, no lo hagas en absoluto. Las pruebas deficientes que no se mantienen, no funcionan bien, etc. pueden ser peores que no tener ninguna prueba. Es difícil de aprender por tu cuenta, y probablemente no te encantará, pero será casi imposible de aprender si no tienes el deseo de hacerlo o no puedes ver el valor suficiente para garantizan la inversión de tiempo.

Un par de personas siguen mencionando que las pruebas ayudan a hacer cumplir la especificación. Según mi experiencia, la especificación también ha sido incorrecta, la mayoría de las veces ...

El teclado de un desarrollador es donde la goma se encuentra con el camino. Si la especificación es incorrecta y no levanta la bandera, entonces es muy probable que lo culpen por ello. O al menos su código lo hará. Es difícil cumplir con la disciplina y el rigor que implican las pruebas. No es nada fácil. Requiere práctica, mucho aprendizaje y muchos errores. Pero finalmente vale la pena. En un proyecto de ritmo rápido y que cambia rápidamente, es la única forma en que puede dormir por la noche, sin importar si lo ralentiza.

Otra cosa en la que pensar aquí es que las técnicas que son fundamentalmente iguales a las pruebas han demostrado funcionar en el pasado: "sala limpia" y "diseño por contrato" tienden a producir los mismos tipos de construcciones de "meta" código que las pruebas hacen, y las hacen cumplir en diferentes puntos. Ninguna de estas técnicas es una fórmula mágica y, en última instancia, el rigor le costará en el alcance de las funciones que puede ofrecer en términos de tiempo de comercialización. Pero no se trata de eso. Se trata de poder mantener lo que entregas. Y eso es muy importante para la mayoría de los proyectos.

lavar
fuente
7

Las pruebas unitarias funcionan de manera muy similar a la contabilidad por partida doble. Declara lo mismo (regla de negocio) de dos formas bastante diferentes (como reglas programadas en su código de producción y como ejemplos simples y representativos en sus pruebas). Es muy poco probable que cometa el mismo error en ambos, por lo que si ambos están de acuerdo, es poco probable que se haya equivocado.

¿Cómo va a valer la pena el esfuerzo realizar las pruebas? En mi experiencia, en al menos cuatro formas, al menos cuando realizo desarrollo basado en pruebas:

  • le ayuda a crear un diseño bien desacoplado. Solo puede realizar pruebas unitarias con código que esté bien desacoplado;
  • le ayuda a determinar cuándo ha terminado. Tener que especificar el comportamiento necesario en las pruebas ayuda a no crear una funcionalidad que en realidad no necesita y a determinar cuándo se completa la funcionalidad;
  • le brinda una red de seguridad para las refactorizaciones, lo que hace que el código sea mucho más receptivo a los cambios; y
  • le ahorra mucho tiempo de depuración, lo cual es terriblemente costoso (he oído estimaciones de que, tradicionalmente, los desarrolladores dedican hasta el 80% de su tiempo a depurar).
Ilja Preuß
fuente
5

La mayoría de las pruebas unitarias, prueban suposiciones. En este caso, el precio de descuento debe ser el precio menos el descuento. Si sus suposiciones son incorrectas, apuesto a que su código también es incorrecto. Y si comete un error tonto, la prueba fallará y la corregirá.

Si las reglas cambian, la prueba fallará y eso es algo bueno. Así que también tienes que cambiar la prueba en este caso.

Como regla general, si una prueba falla de inmediato (y no usa el diseño de prueba primero), la prueba o el código son incorrectos (o ambos si tiene un mal día). Utiliza el sentido común (y posiblemente las especificaciones) para corregir el código infractor y volver a ejecutar la prueba.

Como dijo Jason, las pruebas son seguridad. Y sí, a veces introducen trabajo extra debido a pruebas defectuosas. Pero la mayoría de las veces ahorran mucho tiempo. (Y tienes la oportunidad perfecta para castigar al tipo que rompe la prueba (estamos hablando de gallina de goma)).

Toon Krijthe
fuente
4

Prueba todo lo que puedas. Incluso los errores triviales, como olvidar convertir metros a pies, pueden tener efectos secundarios muy costosos. Escriba una prueba, escriba el código para que lo verifique, haga que pase, siga adelante. Quién sabe, en algún momento en el futuro, alguien puede cambiar el código de descuento. Una prueba puede detectar el problema.

Jim C
fuente
Eso no responde a ninguno de mis pensamientos. Entiendo el mantra básico de TDD ... no veo el beneficio.
FlySwat
4

Veo que las pruebas unitarias y el código de producción tienen una relación simbiótica. En pocas palabras: uno prueba al otro. Y ambos prueban el desarrollador.

Johnsyweb
fuente
3

Recuerde que el costo de reparar los defectos aumenta (exponencialmente) a medida que los defectos pasan por el ciclo de desarrollo. Sí, el equipo de pruebas puede detectar el defecto, pero (generalmente) tomará más trabajo aislar y arreglar el defecto desde ese punto que si una prueba unitaria hubiera fallado, y será más fácil introducir otros defectos mientras se corrige si usted no tiene pruebas unitarias para ejecutar.

Eso suele ser más fácil de ver con algo más que un ejemplo trivial ... y con ejemplos triviales, bueno, si de alguna manera estropea la prueba unitaria, la persona que la revisa detectará el error en la prueba o el error en el código, o ambos. (Están siendo revisados, ¿verdad?) Como señala tvanfosson , las pruebas unitarias son solo una parte de un plan SQA.

En cierto sentido, las pruebas unitarias son un seguro. No son garantía de que detectará todos los defectos y, en ocasiones, puede parecer que está gastando muchos recursos en ellos, pero cuando detectan defectos que puede corregir, gastará mucho menos. que si no se hubiera sometido a ninguna prueba y hubiera tenido que corregir todos los defectos posteriormente.

Dave DuPlantis
fuente
3

Veo su punto, pero claramente está exagerado.

Su argumento es básicamente: las pruebas introducen fallas. Por lo tanto, las pruebas son malas / una pérdida de tiempo.

Si bien eso puede ser cierto en algunos casos, no es la mayoría.

TDD asume: Más pruebas = Menos fallas.

Es más probable que las pruebas detecten puntos de falla que los introduzcan.

Rayo
fuente
1

¡Incluso más automatización puede ayudar aquí! Sí, escribir pruebas unitarias puede suponer mucho trabajo, así que utilice algunas herramientas para ayudarle. Eche un vistazo a algo como Pex, de Microsoft, si está utilizando .Net. Automáticamente creará conjuntos de pruebas unitarias para usted al examinar su código. Aparecerá con pruebas que brinden una buena cobertura, tratando de cubrir todas las rutas a través de su código.

Por supuesto, con solo mirar su código, no puede saber qué estaba tratando de hacer en realidad, por lo que no sabe si es correcto o no. Sin embargo, generará casos de prueba interesantes para usted, y luego podrá examinarlos y ver si se está comportando como espera.

Si luego va más allá y escribe pruebas unitarias parametrizadas (puede pensar en ellas como contratos, en realidad), generará casos de prueba específicos a partir de estos, y esta vez puede saber si algo está mal, porque sus afirmaciones en sus pruebas fallarán.


fuente
1

He pensado un poco en una buena forma de responder a esta pregunta y me gustaría establecer un paralelismo con el método científico. En mi opinión, podría reformular esta pregunta: "¿Cómo se experimenta un experimento?"

Los experimentos verifican los supuestos empíricos (hipótesis) sobre el universo físico. Las pruebas unitarias probarán suposiciones sobre el estado o el comportamiento del código al que llaman. Podemos hablar sobre la validez de un experimento, pero eso es porque sabemos, a través de muchos otros experimentos, que algo no encaja. No tiene validez convergente ni evidencia empírica . No diseñamos un nuevo experimento para probar o verificar la validez de un experimento , pero podemos diseñar un experimento completamente nuevo .

Entonces, al igual que los experimentos , no describimos la validez de una prueba unitaria en función de si pasa o no una prueba unitaria. Junto con otras pruebas unitarias, describe las suposiciones que hacemos sobre el sistema que está probando. Además, como los experimentos, intentamos eliminar la mayor complejidad posible de lo que estamos probando. "Lo más simple posible, pero no más simple".

A diferencia de los experimentos , tenemos un truco bajo la manga para verificar que nuestras pruebas son válidas además de la validez convergente. Podemos introducir inteligentemente un error que sabemos que debería ser detectado por la prueba, y ver si la prueba realmente falla. (¡Si tan solo pudiéramos hacer eso en el mundo real, dependeríamos mucho menos de esta cosa de validez convergente!) Una forma más eficiente de hacer esto es ver que su prueba falla antes de implementarla (el paso rojo en Red, Green, Refactor ).

lavar
fuente
1

Debe usar el paradigma correcto al escribir pruebas.

  1. Comience escribiendo primero sus pruebas.
  2. Asegúrese de que no empiecen con.
  3. Haz que pasen.
  4. Revisión de código antes de verificar su código (asegúrese de que se revisen las pruebas).

No siempre puede estar seguro, pero mejoran las pruebas en general.

Jonathan
fuente
0

Incluso si no prueba su código, seguramente sus usuarios lo probarán en producción. Los usuarios son muy creativos al intentar bloquear su software y encontrar incluso errores no críticos.

Corregir errores en producción es mucho más costoso que resolver problemas en la fase de desarrollo. Como efecto secundario, perderá ingresos debido al éxodo de clientes. Puede contar con 11 clientes perdidos o no ganados por 1 cliente enojado.


fuente