Me pagan por el código que funciona, no por las pruebas, por lo que mi filosofía es probar lo menos posible para alcanzar un nivel de confianza determinado (sospecho que este nivel de confianza es alto en comparación con los estándares de la industria, pero eso podría ser simplemente arrogancia). . Si normalmente no cometo algún tipo de error (como establecer las variables incorrectas en un constructor), no lo pruebo. Tiendo a dar sentido a los errores de prueba, así que soy muy cuidadoso cuando tengo lógica con condicionales complicados. Al programar en un equipo, modifico mi estrategia para probar cuidadosamente el código que, colectivamente, tendemos a equivocarnos.
Diferentes personas tendrán diferentes estrategias de prueba basadas en esta filosofía, pero eso me parece razonable dado el estado inmaduro de comprensión de cómo las pruebas pueden encajar mejor en el ciclo interno de la codificación. Es probable que dentro de diez o veinte años tengamos una teoría más universal sobre qué pruebas escribir, qué pruebas no escribir y cómo diferenciar. Mientras tanto, la experimentación parece estar en orden.
Escriba pruebas unitarias para las cosas que espera romper y para casos extremos. Después de eso, se deben agregar casos de prueba a medida que llegan los informes de errores, antes de escribir la solución para el error. El desarrollador puede estar seguro de que:
Según el comentario adjunto, creo que este enfoque para escribir pruebas unitarias podría causar problemas si, con el tiempo, se descubren muchos errores en una clase determinada. Probablemente aquí es donde la discreción es útil: agregar pruebas unitarias solo para errores que es probable que vuelvan a ocurrir, o donde su reaparición causaría problemas graves. Descubrí que una medida de las pruebas de integración en las pruebas unitarias puede ser útil en estos escenarios: probar el código de las rutas de código más arriba puede cubrir las rutas de código más abajo.
fuente
Una de las cosas más incomprendidas sobre TDD es la primera palabra que contiene. Prueba. Por eso apareció BDD. Porque la gente realmente no entendía que la primera D era la importante, es decir, Driven. Todos tendemos a pensar demasiado en las pruebas y un poco o poco en la conducción del diseño. Y supongo que esta es una respuesta vaga a su pregunta, pero probablemente debería considerar cómo manejar su código, en lugar de lo que realmente está probando; eso es algo con lo que una herramienta de cobertura puede ayudarlo. El diseño es un tema bastante mayor y más problemático.
fuente
Para aquellos que proponen probar "todo": comprendan que "probar completamente" un método como este
int square(int x)
requiere alrededor de 4 mil millones de casos de prueba en lenguajes comunes y entornos típicos.De hecho, es incluso peor que eso: un método
void setX(int newX)
también está obligado no alterar los valores de cualquier otro miembro, además dex
- estás probando queobj.y
,obj.z
, etc., todos permanecen sin cambios después de llamarobj.setX(42);
?Solo es práctico probar un subconjunto de "todo". Una vez que acepta esto, se vuelve más aceptable considerar no probar un comportamiento increíblemente básico. Cada programador tiene una distribución de probabilidad de ubicaciones de errores; el enfoque inteligente es concentrar su energía en las regiones de prueba donde estima que la probabilidad de errores es alta.
fuente
La respuesta clásica es "pruebe cualquier cosa que pueda romperse". Lo interpreto en el sentido de que probar establecedores y captadores que no hacen nada excepto establecer u obtener es probablemente demasiada prueba, no es necesario tomarse el tiempo. A menos que su IDE los escriba por usted, también podría hacerlo.
Si su constructor no establece las propiedades puede generar errores más adelante, probar que están configuradas no es una exageración.
fuente
Escribo pruebas para cubrir los supuestos de las clases que escribiré. Las pruebas hacen cumplir los requisitos. Básicamente, si x nunca puede ser 3, por ejemplo, me aseguraré de que haya una prueba que cubra ese requisito.
Invariablemente, si no escribo una prueba para cubrir una condición, surgirá más tarde durante la prueba "humana". Ciertamente escribiré uno entonces, pero prefiero verlos temprano. Creo que el punto es que las pruebas son tediosas (quizás) pero necesarias. Escribo suficientes pruebas para estar completo, pero nada más.
fuente
Parte del problema de omitir pruebas simples ahora es que en el futuro la refactorización podría hacer que esa propiedad simple sea muy complicada con mucha lógica. Creo que la mejor idea es que puede utilizar Tests para verificar los requisitos del módulo. Si cuando pasa X debe recuperar Y, entonces eso es lo que quiere probar. Luego, cuando cambie el código más adelante, puede verificar que X le da Y, y puede agregar una prueba para A le da B, cuando ese requisito se agregue más adelante.
Descubrí que el tiempo que dedico durante las pruebas de escritura de desarrollo inicial vale la pena en la primera o segunda corrección de errores. La capacidad de recoger el código que no ha mirado en 3 meses y estar razonablemente seguro de que su solución cubre todos los casos, y "probablemente" no rompe nada es muy valiosa. También encontrará que las pruebas unitarias ayudarán a clasificar los errores más allá del seguimiento de la pila, etc. Ver cómo funcionan y fallan las piezas individuales de la aplicación brinda una gran comprensión de por qué funcionan o fallan en su conjunto.
fuente
En la mayoría de los casos, yo diría que si hay lógica, pruébela. Esto incluye constructores y propiedades, especialmente cuando se establece más de una cosa en la propiedad.
Con respecto a demasiadas pruebas, es discutible. Algunos dirían que todo debe probarse para verificar su robustez, otros dicen que para una prueba eficiente, solo se deben probar las cosas que podrían romperse (es decir, la lógica).
Me inclinaría más hacia el segundo campamento, solo por experiencia personal, pero si alguien decidiera probar todo, no diría que fue demasiado ... quizás un poco exagerado para mí, pero no demasiado para ellos.
Entonces, no, yo diría que no existe tal cosa como "demasiadas" pruebas en el sentido general, solo para individuos.
fuente
El desarrollo basado en pruebas significa que deja de codificar cuando pasan todas sus pruebas.
Si no tiene una prueba para una propiedad, ¿por qué debería implementarla? Si no prueba / define el comportamiento esperado en caso de una asignación "ilegal", ¿qué debe hacer la propiedad?
Por lo tanto, estoy totalmente a favor de probar cada comportamiento que una clase debería exhibir. Incluidas las propiedades "primitivas".
Para facilitar esta prueba, creé un NUnit simple
TestFixture
que proporciona puntos de extensión para establecer / obtener el valor y toma listas de valores válidos e inválidos y tiene una sola prueba para verificar si la propiedad funciona correctamente. Probar una sola propiedad podría verse así:Usando lambdas y atributos, esto podría incluso escribirse de manera más compacta. Tengo entendido que MBUnit tiene incluso algo de soporte nativo para cosas como esa. Sin embargo, el punto es que el código anterior captura la intención de la propiedad.
PD: Probablemente PropertyTest también debería tener una forma de verificar que otras propiedades en el objeto no hayan cambiado. Hmm ... de vuelta a la mesa de dibujo.
fuente
Hago prueba unitaria para alcanzar la máxima cobertura factible. Si no puedo alcanzar algún código, refactorizo hasta que la cobertura sea lo más completa posible
Después de terminar la prueba de escritura cegadora, generalmente escribo un caso de prueba que reproduce cada error
Estoy acostumbrado a separar entre pruebas de código y pruebas de integración. Durante las pruebas de integración (que también son pruebas unitarias pero en grupos de componentes, por lo que no son exactamente para qué sirven las pruebas unitarias), probaré para que los requisitos se implementen correctamente.
fuente
Entonces, cuanto más manejo mi programación escribiendo pruebas, menos me preocupo por el nivel de granualidad de las pruebas. Mirando hacia atrás, parece que estoy haciendo lo más simple posible para lograr mi objetivo de validar el comportamiento . Esto significa que estoy generando una capa de confianza de que mi código está haciendo lo que le pido, sin embargo, esto no se considera una garantía absoluta de que mi código esté libre de errores. Siento que el equilibrio correcto es probar el comportamiento estándar y tal vez uno o dos casos extremos y luego pasar a la siguiente parte de mi diseño.
Acepto que esto no cubrirá todos los errores y utilizaré otros métodos de prueba tradicionales para capturarlos.
fuente
Por lo general, empiezo de a poco, con entradas y salidas que sé que deben funcionar. Luego, a medida que soluciono errores, agrego más pruebas para asegurarme de que se prueben las cosas que he solucionado. Es orgánico y me funciona bien.
¿Puedes probar demasiado? Probablemente, pero probablemente sea mejor pecar de cauteloso en general, aunque dependerá de cuán crítica sea su aplicación.
fuente
Creo que debe probar todo en el "núcleo" de su lógica empresarial. Getter ans Setter también porque podrían aceptar un valor negativo o un valor nulo que es posible que no desee aceptar. Si tiene tiempo (siempre depende de su jefe), es bueno probar otra lógica de negocios y todos los controladores que llaman a estos objetos (pasa lentamente de la prueba unitaria a la prueba de integración).
fuente
No realizo pruebas unitarias con métodos simples de establecimiento / obtención que no tienen efectos secundarios. Pero hago pruebas unitarias con todos los demás métodos públicos. Intento crear pruebas para todas las condiciones de contorno en mis algoritmos y verifico la cobertura de mis pruebas unitarias.
Es mucho trabajo pero creo que vale la pena. Prefiero escribir código (incluso código de prueba) que recorrer el código en un depurador. Encuentro que el ciclo de compilación-implementación-depuración de código requiere mucho tiempo y cuanto más exhaustivas son las pruebas unitarias que he integrado en mi compilación, menos tiempo dedico a pasar por ese ciclo de compilación-implementación-depuración de código.
No dijiste por qué también estás codificando arquitectura. Pero para Java uso Maven 2 , JUnit , DbUnit , Cobertura y EasyMock .
fuente
Cuanto más leo sobre él, más creo que algunas pruebas unitarias son como algunos patrones: un olor a lenguajes insuficientes.
Cuando necesita probar si su captador trivial realmente devuelve el valor correcto, es porque puede mezclar el nombre del captador y el nombre de la variable miembro. Ingrese 'attr_reader: name' de ruby, y esto ya no puede suceder. Simplemente no es posible en Java.
Si su getter alguna vez se vuelve no trivial, aún puede agregar una prueba para él.
fuente
Prueba el código fuente que te preocupa.
No es útil probar partes de código en las que está muy seguro, siempre y cuando no cometa errores.
Pruebe las correcciones de errores, para que sea la primera y la última vez que corrija un error.
Pruebe para obtener confianza en partes de código oscuras, de modo que cree conocimiento.
Pruebe antes de la refactorización pesada y media, para no romper las características existentes.
fuente
Esta respuesta es más para averiguar cuántas pruebas unitarias usar para un método dado que sabe que desea probar debido a su criticidad / importancia. Utilizando la técnica Basis Path Testing de McCabe, puede hacer lo siguiente para tener una mayor confianza en la cobertura del código cuantitativamente que la simple "cobertura de declaraciones" o "cobertura de sucursales":
fuente