¿Cómo debe organizarse el código de prueba de unidad de C ++ para obtener la máxima eficiencia de prueba de unidad?

45
  • Esta pregunta no es ni acerca de los marcos de prueba de unidades.
  • Esta pregunta es no sobre la escritura de Pruebas Unitarias.
  • Esta pregunta es sobre donde para colocar el código UT escrito y cómo / cuándo / dónde compilarlo y ejecutarlo.

En Trabajando de manera efectiva con el código heredado , Michael Feathers afirma que

  

buenas pruebas unitarias ... corre rápido

y eso

  

Una prueba de unidad que tarda 1/10 de segundo en ejecutarse es una prueba de unidad lenta.

Creo que estas definiciones tienen sentido. También creo que implican que debes mantener un conjunto de Pruebas de unidad y un conjunto de Esas pruebas de código que demoran más por separado, pero creo que esa es la el precio por el que solo paga una prueba de unidad si se ejecuta (muy) rápidamente.

Obviamente, el problema en C ++ es que para "ejecutar" su prueba de unidad ( s ), debe:

  1. Edite su código (producción o prueba de unidad, según el "ciclo" en el que se encuentre)
  2. compilar
  3. enlace
  4. Ejecutar prueba de unidad ejecutable ( s )

Editar (después de una votación cerrada extraña) : antes de entrar en los detalles, intentaré resumir el punto aquí:

¿Cómo puede organizarse efectivamente el código de prueba unitaria de C ++, de modo que sea eficiente editar el código (de prueba) y ejecutar el código de prueba?

El problema primero es decidir dónde colocar el código de prueba de unidad para que:

  • es "natural" editarlo y verlo en combinación con el código de producción asociado.
  • es fácil / rápido comenzar el ciclo de compilación para la unidad su cambio actual

El segundo problema relacionado es, entonces, lo que debe compilarse para que la retroalimentación sea instantánea.

Opciones extremas:

  • Cada Unidad-Prueba-Prueba-Unidad vive en un archivo cpp separado y este archivo cpp se compila + se vincula por separado (junto con el archivo de unidad de código fuente que prueba) a un solo ejecutable que luego ejecuta esta prueba de unidad.
    • (+) Esto minimiza el tiempo de inicio (compilación + enlace!) para la única unidad de prueba.
    • (+) La prueba se ejecuta súper rápido, porque solo prueba una unidad.
    • (-) La ejecución de toda la suite deberá iniciar un montón de procesos. Puede ser un problema para gestionar.
    • (-) La sobrecarga del inicio del proceso se hará visible
  • El otro lado sería tener - aún - un archivo cpp por prueba, pero todos los archivos cpp de prueba (¡junto con el código que prueban!) están vinculados en un ejecutable (por módulo / proyecto / elija su elección).
    • (+) El tiempo de compilación aún estaría bien, ya que solo se compilará el código modificado.
    • (+) La ejecución de toda la suite es fácil, ya que solo hay que ejecutar un archivo.
    • (-) La suite tardará años en enlazarse, ya que cada recompilación de cualquier objeto activará un nuevo enlace.
    • (-) (?) La demanda demorará más en ejecutarse, aunque si todas las pruebas unitarias son rápidas, el tiempo debería estar bien.

Entonces, ¿cómo se manejan las pruebas unitarias de C ++ en el mundo real ? Si solo ejecuto esas cosas cada noche / hora, la segunda parte realmente no importa, pero la primera parte, a saber, cómo "acoplar" el código UT al código de producción, de modo que es "natural" que los desarrolladores mantengan ambos en El enfoque siempre importa, creo. (Y si los desarrolladores tienen el código UT en foco, querrán ejecutarlo, lo que nos lleva de nuevo a la segunda parte).

¡Historias y experiencias del mundo real apreciadas!

Notas:

  • Esta pregunta deja intencionalmente la plataforma no especificada y el sistema make / project.
  • Preguntas etiquetadas UT & C ++ es un buen lugar para comenzar, pero desafortunadamente muchas preguntas, y especialmente las respuestas, están demasiado centradas en los detalles o en marcos específicos.
  • Hace un tiempo, respondí a pregunta similar sobre la estructura para pruebas de unidades de impulso. Me parece que esta estructura carece de pruebas de unidad "reales" y rápidas. Y encuentro la otra pregunta demasiado estrecha, de ahí esta nueva pregunta.
pregunta Martin Ba 31.08.2011 - 13:25

2 respuestas

6

Tenemos todas las pruebas unitarias (para un módulo) en un ejecutable. Las pruebas se ponen en grupos. Puedo ejecutar una sola prueba (o algunas pruebas) o un grupo de pruebas especificando un nombre (prueba / grupo) en la línea de comandos del corredor de pruebas. El sistema de compilación puede ejecutar el grupo "Generar", el departamento de prueba puede ejecutar "Todos". El desarrollador puede poner algunas pruebas en un grupo como "BUG1234" y 1234 es el número de seguimiento de problemas del caso en el que está trabajando.

    
respondido por el ur. 31.08.2011 - 13:38
6

Primero, no estoy de acuerdo con "1) Edite su código (de producción) y su prueba de unidad". Debe modificar solo uno a la vez, de lo contrario, si el resultado cambia, no sabrá cuál lo causó.

Me gusta colocar pruebas unitarias en un árbol de directorios que sombrea el árbol principal. Si tengo /sources/componentA/alpha/foo.cc y /objects/componentA/beta/foo.o , entonces quiero algo como /UTest_sources/componentA/alpha/test_foo.cc y /UTest_objects/componentA/beta/test_foo.o . Utilizo el mismo árbol de sombra para los objetos de simulacro / código auxiliar y cualquier otra fuente que necesiten las pruebas. Habrá algunos casos de borde, pero este esquema simplifica mucho las cosas. Una buena macro de editor puede extraer la fuente de prueba junto con la fuente del sujeto sin esfuerzo. Un buen sistema de compilación (por ejemplo, GNUMake) puede compilar ambos y ejecutar la prueba con un solo comando (por ejemplo, make test_foo ), y puede administrar varios procesos bazillones, solo aquellos cuyas fuentes han cambiado desde la última vez que se probaron, con bastante facilidad (Nunca he encontrado que la sobrecarga de iniciar estos procesos sea un problema, es O (N)).

En el mismo marco, puede tener pruebas a mayor escala (ya no pruebas unitarias) que vinculan muchos objetos entre sí y ejecutan muchas pruebas. El truco consiste en ordenar estas pruebas por el tiempo que demoran en construirse y ejecutarse, y adaptarlas a su programación diaria en consecuencia. Ejecute la prueba de un segundo o menos cada vez que lo desee; iniciar la prueba de diez segundos y estirar; Prueba de cinco minutos y toma un descanso; Prueba de media hora e ir a almorzar; Prueba de seis horas y vete a casa. Si encuentra que está perdiendo mucho tiempo, por ejemplo. vuelve a vincular una prueba enorme después de cambiar solo un archivo pequeño, lo estás haciendo mal, incluso si la vinculación fuera instantánea, aún estarías ejecutando una prueba larga cuando no se solicitó.

    
respondido por el Beta 31.08.2011 - 18:43

Lea otras preguntas en las etiquetas