unitarias unit tutorial test pruebas net integracion unit-testing tdd

unit testing - tutorial - ¿Hay tal cosa como pruebas unitarias excesivas?



unit test c# (18)

¿En qué punto un desarrollador debe dejar de escribir pruebas unitarias y realizar el trabajo real?

El punto de las pruebas unitarias, además de proporcionar orientación en el diseño , es brindarle retroalimentación sobre si realmente realizó el trabajo. Recuerda ese viejo adagio: si no tiene que funcionar, ya he terminado.

En el vocabulario Lean, las pruebas son "desperdicio necesario", no proporcionan ningún valor directo. Entonces, el arte es escribir solo aquellas pruebas que proporcionan un valor indirecto, al ayudarnos a confiar en que lo que producimos realmente funciona.

Entonces, la mejor guía sobre qué pruebas escribir debe ser su nivel de confianza sobre el código de producción. Ahí es donde el mantra de Extreme Programming "prueba todo lo que podría romperse" proviene de: si algo podría romperse, necesitamos una prueba como nuestra red de seguridad, para poder movernos rápidamente en el futuro, refaccionando con confianza. Si algo "no puede romperse" (como se dice a menudo sobre los accesorios simples), escribir pruebas sería una pérdida total.

Por supuesto, usted falla en su evaluación de vez en cuando. Necesitará experiencia para encontrar el equilibrio correcto. Lo que es más importante, cada vez que obtenga un informe de error en contra de su código, debe pensar en qué tipo de prueba habría evitado que este error salga a la vida salvaje, y evitará errores similares en el futuro. A continuación, agregue este tipo de prueba a su colección de pruebas para el código "que posiblemente podría romperse".

No soy nuevo en el concepto de pruebas unitarias, pero al mismo tiempo aún no los he dominado.

La única pregunta que me ha estado pasando por la cabeza últimamente, ya que he estado escribiendo pruebas unitarias mientras escribo mi código usando la metodología TDD, es: ¿a qué nivel debería estar probando?

A veces me pregunto si estoy siendo excesivo en el uso de pruebas unitarias.

¿En qué punto un desarrollador debe dejar de escribir pruebas unitarias y realizar el trabajo real?

Podría necesitar aclarar esa pregunta antes de que la gente suponga que estoy en contra de usar TDD ...

Lo que estoy luchando es la granularidad de mi prueba ...

  • Cuando mi aplicación tiene un archivo de configuración ¿pruebo que los valores se pueden recuperar del archivo? Me inclino hacia sí ... pero ...
  • ¿Luego escribo una prueba unitaria para cada posible valor de configuración que estará presente? es decir, verificar que existan ... y puedan ser analizados al tipo correcto ...
  • Cuando mi aplicación escribe errores en un registro, ¿necesito probar que puede escribir en el registro? ¿Debo entonces escribir pruebas para verificar que las entradas se realicen realmente en el registro?

Quiero poder usar mis pruebas unitarias para verificar el comportamiento de mi aplicación ... pero no estoy seguro de dónde detenerme. ¿Es posible escribir pruebas que son demasiado triviales?


Creo que una buena prueba prueba un poco de especificación. Cualquier prueba que pruebe algo que no forma parte de una especificación no tiene valor y, por lo tanto, debe omitirse, por ejemplo, los métodos de prueba que son solo medios de implementar la funcionalidad especificada de una unidad. También es cuestionable si vale la pena probar una funcionalidad verdaderamente trivial como getters y setters, aunque nunca se sabe por cuánto tiempo serán triviales.

El problema con las pruebas de acuerdo con las especificaciones es que muchas personas usan las pruebas como especificaciones, lo cual es incorrecto por muchas razones, en parte porque le impide saber realmente qué debe probar y qué no (otra razón importante es que las pruebas son siempre probando solo algunos ejemplos, mientras que las especificaciones siempre deben especificar el comportamiento para todas las posibles entradas y estados).

Si tiene las especificaciones adecuadas para sus unidades (y debería hacerlo), entonces debería ser obvio qué necesita pruebas y cualquier cosa más allá de eso es superflua y, por lo tanto, inútil.


Definitivamente es posible exagerar las pruebas unitarias, y las características de prueba son un buen lugar para comenzar. Pero no pase por alto el manejo de errores de prueba también. Sus unidades deben responder con sensatez cuando se les den entradas que no cumplan con su precondición. Si su propio código es responsable de la entrada incorrecta, una falla de aserción es una respuesta sensata. Si un usuario puede causar una entrada incorrecta, entonces tendrá que probar excepciones de unidades o mensajes de error.

Cada error reportado debería resultar en al menos una prueba unitaria.

En cuanto a algunos de sus detalles: definitivamente probaría mi analizador de archivos de configuración para ver que puede analizar cada valor de cada tipo esperado. (Tiendo a confiar en Lua para los archivos de configuración y el análisis, pero eso todavía me deja con algunas pruebas que hacer.) Pero no escribiría una prueba de unidad para cada entrada en el archivo de configuración; en su lugar, escribiría un marco de prueba basado en tablas que describiría cada entrada posible y generaría las pruebas a partir de eso. Probablemente generaría documentación de la misma descripción. Incluso podría generar el analizador.

Cuando su aplicación escribe entradas en un registro, está virando en las pruebas de integración. Un mejor enfoque sería tener un componente de registro separado como syslog. Luego puede probar el registrador, ponerlo en el estante y reutilizarlo. O mejor aún, reutilice syslog. Una breve prueba de integración puede indicarle si su aplicación está interoperando correctamente con syslog.

En general, si te encuentras escribiendo muchas pruebas unitarias, quizás tus unidades sean demasiado grandes y no lo suficientemente ortogonales.

Espero que algo de esto ayude.


En la práctica, el problema no es que las personas escriban demasiadas pruebas, sino que distribuyen sus pruebas de forma desigual. Algunas veces verá que las personas que son nuevas en las pruebas unitarias escriben cientos de pruebas para las cosas que son fáciles de probar, pero luego se agotan antes de realizar las pruebas donde más se necesitan.


En las pruebas unitarias, debe escribir una prueba que demuestre que es posible leer elementos de los archivos de configuración. Usted probaría cualquier capricho posible para que tenga un conjunto representativo de pruebas, por ejemplo, ¿puede leer una cadena vacía, o una cadena larga, o una cadena con caracteres escapados, puede el sistema distinguir entre una cadena vacía o faltante?

Con esa prueba realizada, no es necesario volver a verificar esa capacidad cada vez que otra clase use la instalación que ya ha probado. De lo contrario, para cada función que pruebe, tendrá que volver a probar cada función del sistema operativo en la que se basa. Las pruebas para una función determinada solo necesitan probar cuál es el código de esa función responsable de hacerlo bien.

A veces, si esto es difícil de juzgar, indica algo que necesita una refactorización para que la pregunta sea más fácil de responder. Si tiene que escribir la misma prueba muchas veces para diferentes características, esto puede indicar que esas características comparten algo dentro de ellas que podría moverse a una única función o clase, probarse una vez y luego reutilizarse.

En términos más amplios, esta es una cuestión de economía. Suponiendo que haya suspendido innecesariamente las pruebas duplicadas, ¿cuánto puede pagar para que las pruebas estén completas? Es efectivamente imposible escribir pruebas genuinamente completas para cualquier programa no trivial debido a la combinación de circunstancias que pueden ocurrir, por lo que debe realizar la llamada. Muchos productos exitosos se han apoderado del mundo a pesar de no tener pruebas unitarias cuando se lanzaron originalmente, incluidas algunas de las aplicaciones de escritorio más famosas de todos los tiempos. No eran confiables, pero lo suficientemente buenos, y si habían invertido más en la confiabilidad, entonces sus competidores los habrían derrotado al primer lugar en la participación en el mercado. (Miren a Netscape, que obtuvo el primer lugar con un producto que era notoriamente poco confiable, y luego se extinguió completamente cuando se tomaron el tiempo para hacer todo de la manera correcta). Esto no es lo que nosotros, como ingenieros, queremos escuchar, y espero que en estos días los clientes sean más exigentes, pero sospecho que no mucho.


Es muy posible, pero el problema no es tener demasiadas pruebas: está probando cosas que no te importan, o inviertes demasiado en probar cosas menos y pruebas más simples hubieran sido suficientes.

Mi principio rector es el nivel de confianza que tengo cuando cambio una pieza de código: si nunca falla, no necesitaré la prueba. Si es sencillo, una simple cordura servirá. Si es complicado, enciendo las pruebas hasta que me sienta seguro para hacer cambios.


Las pruebas unitarias deben probar cada pieza de funcionalidad, casos extremos y, a veces, casos de esquina.

Si encuentra que después de probar casos de borde y esquina, está haciendo casos "medios", entonces eso probablemente sea excesivo.

Además, dependiendo de su entorno, las pruebas unitarias pueden consumir mucho tiempo o ser bastante frágiles.

Las pruebas requieren un mantenimiento continuo, por lo que cada prueba que escriba potencialmente se romperá en el futuro y será necesario repararla (aunque no se haya detectado un error real): intentar hacer pruebas suficientes con el mínimo de pruebas parece ser un buen objetivo ( pero no solo improvise varias pruebas en una innecesariamente, pruebe una cosa a la vez)


Las pruebas unitarias excesivas a menudo surgen cuando se usa generación de código para generar pruebas unitarias realmente obvias. Sin embargo, dado que las pruebas de unidades generadas en realidad no hacen daño a nadie (y no afectan negativamente la relación costo-beneficio), les digo que las dejen en su lugar; podrían ser útiles cuando menos lo esperen.


Por supuesto, uno puede sobreestimar de la misma manera que uno puede sobre-diseñar.

A medida que sigas el desarrollo basado en pruebas, deberás ganar confianza sobre tu código y detenerte cuando tengas la confianza suficiente. En caso de duda, agregue una nueva prueba.

Acerca de las pruebas triviales, un proverbio eXtreme Programming sobre esto es " probar todo lo que pueda romperse ".


Sí, de hecho es posible escribir cantidades excesivas de pruebas unitarias. Por ejemplo,

  • probar getters y setters.
  • probando que la funcionalidad básica del lenguaje funciona.

Si dos casos de prueba se ejecutarán exactamente el mismo código, entonces no hay necesidad de probarlos por separado. Por ejemplo, para su ejemplo de lectura del archivo de configuración, solo necesita probar que es capaz de leer correctamente cada tipo de valor (y que falla de la manera correcta cuando se le pide que lea un valor inexistente o no válido).

Si prueba que lee correctamente en cada valor en el archivo de configuración, entonces está probando el archivo de configuración, no el código.


Una cosa a tener en cuenta, basada en algunas de las respuestas dadas, es que si encuentra que necesita escribir numerosas pruebas unitarias para hacer lo mismo una y otra vez, considere refactorizar la causa raíz del código en cuestión.

¿Necesita escribir una prueba para todos los lugares donde accede a una configuración? No. Puede probarlo una vez si refactoriza y crea un único punto de entrada para la funcionalidad. Creo en probar la mayor cantidad de funcionalidad posible. Pero es realmente importante darse cuenta de que si omite el paso de refactorización, la cobertura de su código se desplomará a medida que continúe teniendo implementaciones "únicas" en toda la base del código.


La metodología TDD se trata de diseñar : tener un conjunto de pruebas para más adelante es un efecto secundario bastante bienvenido. El desarrollo impulsado por pruebas revela un código completamente diferente a tener las pruebas "solo" como una ocurrencia tardía.

Por lo tanto, cuando pregunta en el contexto de TDD: es fácil diseñar excesivamente una solución que es "sobreestimulada". Deténgase cuando tenga el diseño lo suficientemente fijo como para que no se deslice. No es necesario atornillarlo, sujetarlo y cubrirlo con cemento. Necesita que el diseño sea lo suficientemente flexible como para cambiarlo durante la próxima refactorización.

Mi historia personal para las pruebas sobredimensionadas es una prueba sobre la que se ridiculizó, donde la implementación de algunas clases se reflejó más o menos en llamadas de ''espera'' a los respectivos objetos simulados. Hable sobre la resistencia a adoptar a los requisitos modificados ...


Si pasa todo el tiempo de depuración en las rutinas de prueba, es posible que se haya excedido.


Creo que esta regla también debería aplicarse a TDD para evitar una excesiva prueba unitaria.


[Actualización:] Encontró la respuesta concisa a esta pregunta en TDD ByExample - Pg194.

La respuesta simple, proporcionada por Phlip es: "Escribe pruebas hasta que el miedo se transforme en aburrimiento".

[/ Update ]

Creo que el problema que prevalece en los tiempos actuales es la falta de pruebas unitarias ... no pruebas excesivas. Creo que veo a lo que te refieres ... No lo llamaría pruebas unitarias excesivas, sino más bien ... no ser inteligente acerca de dónde enfocas tus esfuerzos.

Entonces para responder a su pregunta ... algunas pautas.

  • Si sigues TDD , nunca tendrás un código que no esté cubierto por una prueba de unidad ... ya que solo escribes un código (mínimo) para pasar una prueba de falla de unidad y nada más. Corolario: cada problema debe fallar en una prueba unitaria que indique la ubicación del defecto. El mismo defecto no debe causar que decenas de UT se rompan simultáneamente
  • No pruebes el código que no escribiste. Un corolario es: no prueba el código de la estructura (como leer los valores de un archivo app.config). Simplemente asume que funciona. ¿Y cuántas veces has tenido un código de framework que se rompe? Al lado de cero.
  • En caso de duda, considere la probabilidad de falla y pondere eso con el costo de escribir un caso de prueba automatizado . Escritura de casos de prueba para accedores / pruebas de conjuntos de datos repetitivos incluidos.
  • Abordar el dolor . Si encuentra que tiene problemas en cierta área periódicamente, hágalo bajo un arnés de prueba ... en lugar de perder tiempo escribiendo pruebas redundantes para áreas que usted sabe que son bastante sólidas. Por ejemplo, una biblioteca de un tercero / equipo sigue rompiendo en la interfaz ... no funciona como debería. Mocks no lo atrapará. Disponga de un conjunto de tipos de regresión con el colaborador real y ejecute algunas pruebas de cordura para verificar el enlace si sabe que ha sido un niño problemático.

Para determinar cuánto esfuerzo de prueba pongo en un programa, defino los criterios para esta campaña de prueba en términos de lo que se probará: todas las ramas del código, todas las funciones, todos los dominios de entrada o salida, todas las características. ..

Dado esto, mi trabajo de prueba finaliza cuando mis criterios están completamente cubiertos.

Solo necesito ser consciente de que ciertos objetivos son imposibles de alcanzar, como todas las rutas del programa o todos los valores de entrada.


sí, las pruebas unitarias pueden tomarse en exceso / extremos

tenga en cuenta que solo es necesario probar las funciones ; todo lo demás se sigue de eso

así que no, no tienes que probar que puedes leer valores de un archivo de configuración, porque una (o más) de las características necesitarán leer valores de un archivo de configuración, y si no lo hacen, entonces no lo harás. Necesito un archivo de configuración!

EDITAR: Parece haber cierta confusión en cuanto a lo que trato de decir. No estoy diciendo que las pruebas unitarias y las pruebas de características sean la misma cosa, no lo son. Por wikipedia : "una unidad es la parte más pequeña comprobable de una aplicación" y, lógicamente, esas "unidades" son más pequeñas que la mayoría de las "características".

Lo que estoy diciendo es que las pruebas unitarias son extremas, y rara vez son necesarias, con la posible excepción de software supercrítico (sistemas de control en tiempo real donde las vidas pueden estar en peligro, por ejemplo) o proyectos sin límites de presupuesto y línea de tiempo .

Para la mayoría del software, desde un punto de vista práctico, las características de prueba son todo lo que se requiere. Las unidades de prueba más pequeñas que las características no dolerá, y podría ayudar, pero la compensación en la productividad frente a las mejoras en la calidad es discutible.