Realmente me enamoré de las pruebas unitarias y TDD. Estoy infectado con las pruebas.
Sin embargo, las pruebas unitarias se usan normalmente para métodos públicos. A veces, aunque tengo que probar algunas suposiciones-aserciones en métodos privados también, porque algunas de ellas son "peligrosas" y la refactorización no puede ayudar más. (Lo sé, los marcos de prueba permiten probar métodos privados).
Entonces se convirtió en un hábito mío que la primera y la última línea de un método privado sean ambas afirmaciones.
Sin embargo, he notado que tiendo a usar aserciones en métodos públicos (así como en los privados) solo "para estar seguro". ¿Podría ser esto "prueba de duplicación" dado que los supuestos de métodos públicos son probados desde el exterior por el marco de prueba de la unidad?
¿Podría alguien pensar en demasiadas afirmaciones como un olor a código?
fuente
Respuestas:
Esas afirmaciones son realmente útiles para probar sus suposiciones, pero también sirven para otro propósito realmente importante: la documentación. Cualquier lector de un método público puede leer las afirmaciones para determinar rápidamente las condiciones previas y posteriores, sin tener que mirar el conjunto de pruebas. Por esta razón, le recomiendo que guarde esas afirmaciones por razones de documentación, en lugar de razones de prueba. Técnicamente estás duplicando las afirmaciones, pero tienen dos propósitos diferentes y son muy útiles en ambos.
Mantenerlos como afirmaciones es mejor que simplemente usar comentarios, porque verifican activamente los supuestos cada vez que se ejecutan.
fuente
Parece que estás tratando de hacer Diseño por contrato a mano.
Hacer DbC es una buena idea, pero al menos debería considerar cambiar a un lenguaje que lo admita de forma nativa (como Eiffel ) o al menos usar un marco de contrato para su plataforma (por ejemplo, Microsoft Code Contracts para .NETes bastante agradable, posiblemente el marco de contrato más sofisticado que existe, incluso más poderoso que Eiffel). De esa manera, puede aprovechar mejor el poder de los contratos. Por ejemplo, utilizando un marco existente, puede mostrar los contratos en su documentación o un IDE (por ejemplo, los contratos de código para .NET se muestran en IntelliSense y, si tiene VS Ultimate, incluso puede comprobarse estáticamente por un probador de teoremas automático en tiempo de compilación mientras escribe; asimismo, muchos marcos de contratos Java tienen doclets JavaDoc que extraerán automáticamente los contratos en la documentación de su API JavaDoc).
E incluso si resulta que en su situación no hay alternativa a hacerlo manualmente, ahora al menos sabe cómo se llama y puede leer sobre ello.
En resumen: si realmente está haciendo DbC, incluso si no lo sabe, esas afirmaciones están perfectamente bien.
fuente
Siempre que no tenga control total sobre sus parámetros de entrada, es una muy buena idea probar por adelantado los errores simples. Falla en nulo por ejemplo.
Esta no es la duplicación de las pruebas, ya que debe probar que el código falla apropiada dada parámetros de entrada incorrecta, y luego documentar que .
No creo que deba afirmar los parámetros de retorno (a menos que explícitamente tenga una invariante que quiera que el lector entienda). Este es también el trabajo de las pruebas unitarias.
Personalmente, no me gusta la
assert
declaración en Java, ya que se pueden desactivar y es una falsa seguridad.fuente
Creo que usar afirmaciones en métodos públicos es aún más importante, ya que allí no controlas las entradas y es más probable que se rompa una suposición.
Las condiciones de entrada de prueba deben realizarse en todos los métodos públicos y protegidos. Si las entradas se pasan directamente a un método privado, entonces probar sus entradas puede ser redundante.
Las condiciones de salida de prueba (por ejemplo, el estado del objeto o ese valor de retorno! = Nulo) deben realizarse en los métodos internos (por ejemplo, métodos privados). Si las salidas se pasan directamente de un método privado a la salida de un método público sin cálculos adicionales o cambios de estado interno, entonces probar las condiciones de salida del método público puede ser redundante.
Sin embargo, estoy de acuerdo con Oleksi en que la redundancia puede aumentar la legibilidad y también puede aumentar la capacidad de mantenimiento (si la asignación directa o la devolución ya no es el caso en el futuro).
fuente
Es difícil ser independiente del lenguaje sobre este problema, ya que los detalles de cómo se implementan las aserciones y el manejo 'apropiado' de errores / excepciones tienen relación con la respuesta. Aquí están mis $ 0.02, basados en mi conocimiento de Java y C ++.
Las afirmaciones en métodos privados son una buena cosa, suponiendo que no se exceda y las ponga en todas partes . Si los está poniendo en métodos realmente simples o verificando repetidamente cosas como campos inmutables, entonces está abarrotando el código innecesariamente.
Por lo general, es mejor evitar las afirmaciones en métodos públicos. Todavía debe hacer cosas como verificar que el contrato del método no se viole, pero si lo es, entonces debería lanzar excepciones adecuadamente tipadas con mensajes significativos, revertir el estado donde sea posible, etc. (lo que @rwong llama "el total tratamiento adecuado de manejo de errores ").
En términos generales, solo debe usar aserciones para ayudar a su desarrollo / depuración. No puede asumir que quien use su API tendrá habilitadas las aserciones cuando use su código. Aunque tienen algún uso para ayudar a documentar el código, a menudo hay mejores formas de documentar las mismas cosas (es decir, documentación del método, excepciones).
fuente
Agregar a la lista de respuestas (en su mayoría) excepcionales, otra razón para muchas afirmaciones y duplicaciones, es que no sabes cómo, cuándo o por quién se modificará la clase durante su vida útil. Si está escribiendo un código desechable que estará muerto en un año, no es una preocupación. Si está escribiendo un código que estará en uso en más de 20 años, se verá bastante diferente, y una suposición que haya hecho puede que ya no sea válida. El tipo que hace ese cambio te agradecerá por las afirmaciones.
Además, no todos los programadores son perfectos; de nuevo, las afirmaciones significan que uno de esos "errores" no se propagará demasiado.
No subestime el efecto que estas afirmaciones (y otras verificaciones sobre los supuestos) tendrán en la reducción del costo de mantenimiento.
fuente
Tener afirmaciones duplicadas no está mal per se, pero tener las afirmaciones "solo para asegurarse" no es lo mejor. Realmente se reduce a lo que exactamente cada prueba está tratando de lograr. Solo afirme lo que es absolutamente necesario. Si una prueba usa Moq para verificar que se invoca un método, en realidad no importa lo que suceda después de invocar ese método, la prueba solo se preocupa por asegurarse de que se invoque el método.
Si cada prueba de unidad individual tiene el mismo conjunto de afirmaciones, excepto una o dos, entonces cuando refactoriza un poco, todas las pruebas pueden fallar exactamente por la misma razón, en lugar de mostrarte el verdadero impacto del refactor. Podrías terminar en una situación en la que ejecutas todas las pruebas, todas fallan porque cada prueba tiene las mismas afirmaciones, corriges esa falla, ejecutas las pruebas nuevamente, fallan por otra razón, corriges esa falla. Repita hasta que esté listo.
También considere el mantenimiento de su proyecto de prueba. ¿Qué sucede cuando agrega un nuevo parámetro, o la salida se modifica ligeramente, tendría que volver a pasar por un montón de pruebas y cambiar una afirmación o agregar una afirmación? Y, dependiendo de su código, podría terminar teniendo que configurar mucho más solo para asegurarse de que todas las afirmaciones pasen.
Puedo entender el atractivo de querer incluir afirmaciones duplicadas en la prueba unitaria, pero realmente es exagerado. Seguí el mismo camino con mi primer proyecto de prueba. Me alejé porque el mantenimiento solo me estaba volviendo loco.
fuente
Si su marco de prueba permite accesores, entonces la prueba unitaria de métodos privados también es una buena idea (IMO).
Hago. Las afirmaciones están bien, pero su primer objetivo debe ser lograr que el escenario ni siquiera sea posible ; no solo que no suceda.
fuente
Es una mala practica.
No debe probar métodos públicos / privados. Debes probar la clase como un todo. Solo asegúrese de tener una buena cobertura.
Si sigue la forma (primitiva) de probar cada método por separado como regla general, le resultará extremadamente difícil refactorizar su clase en el futuro. Y esa es una de las mejores cosas que TDD le permite hacer.
Además, es duplicación. Además, sugiere que el escritor del código realmente no sabía lo que estaba haciendo. Y lo curioso es que sí .
Algunas personas tratan sus pruebas con menos cuidado que su código de producción. No deberían. En todo caso, mi experiencia sugiere incluso tratar las pruebas con más cuidado. Valen la pena
fuente