¿Son las aserciones o las pruebas unitarias más importantes?

50

Tanto las aserciones 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 afirma que la función es como comprobaciones de sanidad y ver entradas reales, mientras que las pruebas unitarias se ejecutan en entradas simuladas específicas y se comparan con una única "respuesta correcta" bien definida. ¿Cuáles son los méritos relativos del uso de aserciones frente a pruebas unitarias como los medios principales para verificar la corrección? ¿Cuál crees que debería enfatizarse más?

    
pregunta dsimcha 11.11.2010 - 05:19

3 respuestas

43

Las aserciones 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 estructura de datos Time no tendrá el valor de 25:61:61 . Las condiciones verificadas por aserciones son:

  • Condiciones previas, que aseguran que la persona que llama mantiene su contrato,

  • Postcondiciones, 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. Un 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 . Su Stack puede tener un estado consistente después de que se llame al método push() , 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 en el que la implementación push() incorrecta solo verifica las afirmaciones y las salidas).

Estrictamente hablando, la principal diferencia entre aserciones y pruebas unitarias es que las pruebas unitarias tienen datos de prueba (valores para que el programa se ejecute), mientras que las aseveraciones no. Es decir, puede ejecutar las pruebas unitarias automáticamente, mientras que no puede decir lo mismo para las afirmaciones. Por el bien de esta discusión, asumí que está hablando de ejecutar el programa en el contexto de las pruebas de función de orden superior (que ejecutan todo el programa y no manejan módulos como las pruebas unitarias). Si no está hablando de pruebas de función automatizadas como los medios para "ver entradas reales", entonces claramente el valor está en la automatización, y por lo tanto las pruebas de unidad ganarán. Si está hablando de esto en el contexto de las pruebas de función (automatizadas), consulte a continuación.

Puede haber alguna superposición en lo que se está probando. Por ejemplo, una condición posterior de Stack 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 pruebas unitarias, el objetivo es encontrar errores. Para las afirmaciones, el objetivo es facilitar la depuración mediante la observación de estados de programa no válidos tan pronto como ocurran.

Tenga en cuenta que la técnica ni verifica la corrección. De hecho, si realiza pruebas de unidad con el objetivo de verificar que el programa es correcto, es probable que surja una prueba poco interesante que sepa 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 una nota final sobre las aserciones: para obtener el mayor 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 ser difícil de detectar sin horas de depuración.]

    
respondido por el Macneil 11.11.2010 - 06:06
7

Cuando hable sobre aserciones, tenga en cuenta que pueden apagarse con solo presionar un botón.

Ejemplo de una afirmación muy mala:

char *c = malloc(1024);
assert(c != NULL);

¿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.

Una prueba de unidad (probablemente) simplemente segregará en el código anterior. Claro, hizo su trabajo diciéndole que algo salió mal, ¿o no? ¿Qué posibilidades hay de que malloc() falle en la prueba?

Las aserciones son para propósitos de depuración cuando un programador debe implicar que ningún evento "normal" causaría que la aserción se dispare. malloc() que falla es, de hecho, un evento normal, por lo tanto, nunca debe ser confirmado.

Hay muchos otros casos en los que se usan aserciones en lugar de manejar adecuadamente las cosas que podrían salir mal. Esta es la razón por la cual las aserciones obtienen una mala reputación y los lenguajes como Go no los incluyen.

Las pruebas unitarias están diseñadas para decirle cuándo algo que cambió se rompió algo más. Están diseñados para evitar que (en la mayoría de los casos) evites todas las funciones del programa (sin embargo, los evaluadores son importantes para los lanzamientos) cada vez que realizas una compilación.

Realmente no hay una correlación distinta entre los dos, excepto que ambos te dicen que algo salió mal. Piense en una afirmación como un punto de ruptura en algo en lo que está trabajando, sin tener que usar un depurador. Piense en una prueba de unidad como algo que le dice si rompió algo en lo que no está trabajando.

    
respondido por el Tim Post 11.11.2010 - 05:45
5

Ambas son herramientas utilizadas para ayudar a mejorar la calidad general del sistema que está creando. Mucho depende del idioma que esté utilizando, del tipo de aplicación que está creando y de la mejor manera de gastar su tiempo. Sin mencionar que tienes algunas escuelas de pensamiento al respecto.

Para comenzar, si está usando un idioma sin una palabra clave assert , no puede usar aserciones (al menos no de la forma en que estamos hablando aquí). Durante mucho tiempo, Java no tenía una palabra clave assert , y varios idiomas aún no lo tienen. La prueba de unidad entonces se vuelve un poco más importante. 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 significativo if / throw . Este proceso de pensamiento proviene de muchas afirmaciones colocadas al comienzo de un método para asegurar 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.

La prueba de unidad es un código adicional que se debe escribir y mantener. Para muchos esto es un inconveniente. Sin embargo, con el recorte actual de marcos de prueba de unidad por ahí, puede generar un mayor número de condiciones de prueba con un código comparativamente pequeño. Las pruebas parametrizadas y las "teorías" realizarán la misma prueba con una gran cantidad de muestras de datos que pueden descubrir algunos errores difíciles de encontrar.

Personalmente encuentro que obtengo más kilometraje con las pruebas unitarias que las aserciones 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 aserción más sólido, 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 unidad.

enlace

    
respondido por el Berin Loritsch 11.11.2010 - 05:51

Lea otras preguntas en las etiquetas