Tanto las afirmaciones como las pruebas unitarias sirven como documentación para una base de código y un medio para descubrir errores. Las principales diferencias son que las afirmaciones funcionan como verificaciones de cordura y ven entradas reales, mientras que las pruebas unitarias se ejecutan en entradas simuladas específicas y son pruebas contra una única "respuesta correcta" bien definida. ¿Cuáles son los méritos relativos de usar afirmaciones versus pruebas unitarias como el medio principal para verificar la corrección? ¿Cuál crees que debería enfatizarse más?
testing
unit-testing
assertions
dsimcha
fuente
fuente
:-)
Respuestas:
Las afirmaciones son útiles para informarle sobre el estado interno del programa . Por ejemplo, que sus estructuras de datos tienen un estado válido, por ejemplo, que una
Time
estructura de datos no tendrá el valor de25:61:61
. Las condiciones verificadas por afirmaciones son:Condiciones previas, que aseguran que la persona que llama mantiene su contrato,
Condiciones posteriores, que aseguran que la persona que llama mantiene su contrato, y
Invariantes, que aseguran que la estructura de datos siempre tenga alguna propiedad después de que la función regrese. Una invariante es una condición que es una condición previa y una condición posterior.
Las pruebas unitarias son útiles para informarle sobre el comportamiento externo del módulo . Es
Stack
posible que tenga un estado consistente después depush()
que se llame al método, pero si el tamaño de la pila no aumenta en tres después de que se llama tres veces, entonces eso es un error. (Por ejemplo, el caso trivial donde lapush()
implementación incorrecta solo verifica las afirmaciones y las salidas).En sentido estricto, la principal diferencia entre las afirmaciones y las pruebas unitarias es que las pruebas unitarias tienen datos de prueba (valores para que el programa se ejecute), mientras que las afirmaciones no. Es decir, puede ejecutar sus pruebas unitarias automáticamente, mientras que no puede decir lo mismo para las afirmaciones. En aras de esta discusión, he asumido que está hablando de ejecutar el programa en el contexto de pruebas de función de orden superior (que ejecutan todo el programa y no controlan módulos como pruebas unitarias). Si no está hablando de las pruebas de función automatizadas como el medio para "ver entradas reales", entonces claramente el valor radica en la automatización y, por lo tanto, las pruebas unitarias ganarían. Si está hablando de esto en el contexto de las pruebas de función (automatizadas), consulte a continuación.
Puede haber cierta superposición en lo que se está probando. Por ejemplo,
Stack
la condición posterior de una realidad puede afirmar que el tamaño de la pila aumenta en uno. Pero hay límites a lo que se puede realizar en esa afirmación: ¿Debería también verificar que el elemento superior es lo que se acaba de agregar?Para ambos, el objetivo es aumentar la calidad. Para las pruebas unitarias, el objetivo es encontrar errores. Para las afirmaciones, el objetivo es facilitar la depuración observando estados de programa no válidos tan pronto como ocurran.
Tenga en cuenta que ninguna de las técnicas verifica la corrección. De hecho, si realiza pruebas unitarias con el objetivo de verificar que el programa sea correcto, probablemente obtendrá una prueba poco interesante que sabe que funcionará. Es un efecto psicológico: harás lo que sea para cumplir tu objetivo. Si su objetivo es encontrar errores, sus actividades reflejarán eso.
Ambos son importantes y tienen sus propios propósitos.
[Como nota final sobre las afirmaciones: para obtener el máximo valor, debe usarlas en todos los puntos críticos de su programa y no en algunas funciones clave. De lo contrario, la fuente original del problema podría haber sido enmascarada y difícil de detectar sin horas de depuración.]
fuente
Cuando hable de afirmaciones, tenga en cuenta que se pueden desactivar con solo pulsar un interruptor.
Ejemplo de una afirmación muy mala:
¿Por qué es esto malo? Porque no se realiza ninguna comprobación de errores si se omite esa afirmación debido a que se está definiendo algo como NDEBUG.
(Probablemente) una prueba unitaria solo sería predeterminada en el código anterior. Claro, hizo su trabajo al decirle que algo salió mal, ¿o no? ¿Qué posibilidades hay de
malloc()
que falle en la prueba?Las afirmaciones son para propósitos de depuración cuando un programador necesita implicar que ningún evento 'normal' causaría que la afirmación se disparara.
malloc()
fallar es, de hecho, un evento normal, por lo tanto, nunca debe afirmarse.Hay muchos otros casos en los que se utilizan aserciones en lugar de manejar adecuadamente las cosas que podrían salir mal. Esta es la razón por la cual las afirmaciones tienen mala reputación, y por qué los idiomas como Go no las incluyen.
Las pruebas unitarias están diseñadas para informarle cuando algo que cambió rompió con otra cosa. Están diseñados para salvarlo (en la mayoría de los casos) de pasar por todas las funciones del programa (sin embargo, los probadores son importantes para las versiones) cada vez que realiza una compilación.
Realmente no hay una correlación clara entre los dos, aparte de que ambos te dicen que algo salió mal. Piense en una afirmación como un punto de interrupción en algo en lo que está trabajando, sin tener que usar un depurador. Piense en una prueba unitaria como algo que le dice si rompió algo en lo que no está trabajando.
fuente
Ambas son herramientas utilizadas para ayudar a mejorar la calidad general del sistema que está creando. Mucho depende del idioma que esté utilizando, el tipo de aplicación que está creando y dónde se dedica mejor su tiempo. Sin mencionar que tienes algunas escuelas de pensamiento al respecto.
Para comenzar, si está usando un idioma sin una
assert
palabra clave, no puede usar afirmaciones (al menos no en la forma en que estamos hablando aquí). Durante mucho tiempo, Java no tenía unaassert
palabra clave, y varios idiomas todavía no. Las pruebas unitarias se vuelven bastante más importantes. En algunos idiomas, las aserciones solo se ejecutan cuando se establece un indicador (nuevamente con Java aquí). Cuando las protecciones no siempre están ahí, no es una característica muy útil.Hay una escuela de pensamiento que dice que si está "afirmando" algo, también podría escribir un bloque de excepción
if
/throw
significativo. Este proceso de pensamiento proviene de muchas afirmaciones colocadas al comienzo de un método para garantizar que todos los valores estén dentro de los límites. Probar sus condiciones previas es una parte muy importante de tener una condición posterior esperada.Las pruebas unitarias son códigos adicionales que deben escribirse y mantenerse. Para muchos esto es un inconveniente. Sin embargo, con la actual cosecha de marcos de prueba unitarios, puede generar una mayor cantidad de condiciones de prueba con un código relativamente pequeño. Las pruebas y "teorías" parametrizadas realizarán la misma prueba con una gran cantidad de muestras de datos que pueden descubrir algunos errores difíciles de encontrar.
Personalmente, descubro que obtengo más kilometraje con las pruebas unitarias que con las aspersiones por aspersión, pero eso se debe a las plataformas que desarrollo la mayor parte del tiempo (Java / C #). Otros idiomas tienen un soporte de afirmación más robusto e incluso "Diseño por contrato" (ver más abajo) para proporcionar aún más garantías. Si estuviera trabajando con uno de estos idiomas, podría usar el DBC más que la prueba de la unidad.
http://en.wikipedia.org/wiki/Design_by_contract#Languages_with_native_support
fuente