- Esta pregunta no se trata de marcos de prueba de unidad.
- Esta pregunta no se trata de escribir pruebas unitarias.
- Esta pregunta es sobre dónde poner el código UT escrito y cómo / cuándo / dónde compilarlo y ejecutarlo.
Al trabajar eficazmente con el código heredado , Michael Feathers afirma que
buenas pruebas unitarias ... corre rápido
y eso
Una prueba unitaria que tarda 1/10 de segundo en ejecutarse es una prueba unitaria lenta.
Creo que estas definiciones tienen sentido. También creo que implican que debe mantener un conjunto de Pruebas unitarias y un conjunto de Pruebas de código que toman más tiempo por separado, pero supongo que ese es el precio que paga por llamar a algo como Prueba unitaria si se ejecuta (muy) rápido .
Obviamente, el problema en C ++ es que para "ejecutar" su ( s ) Prueba ( s ) de Unidad , debe:
- Edite su código (producción o prueba unitaria, según el "ciclo" en el que se encuentre)
- Compilar
- Enlazar
- Iniciar unidad de prueba Ejecutable ( s )
Editar (después de una votación cerrada) : antes de entrar en detalles, intentaré resumir el punto aquí:
¿Cómo se puede organizar eficazmente el código de prueba unitaria de C ++, de modo que sea eficiente editar el código (prueba) y ejecutar el código de prueba?
El primer problema 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 de la unidad que está cambiando actualmente
El segundo problema relacionado es qué compilar 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 + enlaza por separado (junto con el archivo de unidad de código fuente que prueba) a un único ejecutable que luego ejecuta esta Prueba unitaria.
- (+) Esto minimiza el tiempo de inicio (¡compilación + enlace!) Para la Unidad de Prueba individual.
- (+) La prueba se ejecuta muy rápido, ya que solo prueba una unidad.
- (-) La ejecución de toda la suite necesitará iniciar una gran cantidad 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 / por proyecto / elija su elección).
- (+) El tiempo de compilación aún estaría bien, ya que solo se compilará el código modificado.
- (+) Ejecutar toda la suite es fácil, ya que solo hay un exe para ejecutar.
- (-) La suite tardará años en vincularse, ya que cada compilación de cualquier objeto activará un reenlace.
- (-) (?) El traje tardará 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 C ++ del mundo real ? Si solo ejecuto esas cosas cada noche / hora, la segunda parte realmente no importa, pero la primera parte, es decir, cómo "acoplar" el código UT al código de producción, de modo que sea "natural" para los desarrolladores mantener 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 vuelta a la segunda parte).
¡Historias y experiencias del mundo real apreciadas!
Notas:
- Esta pregunta deja intencionalmente una plataforma no especificada y un sistema de creación / proyecto.
- Preguntas etiquetadas UT & C ++ es un excelente lugar para comenzar, pero desafortunadamente muchas preguntas, y especialmente las respuestas, se centran demasiado en los detalles o en marcos específicos.
- Hace un tiempo, respondí una pregunta similar sobre la estructura de las pruebas de unidad de refuerzo. Encuentro que esta estructura es insuficiente para las pruebas de unidad "reales" y rápidas. Y encuentro la otra pregunta demasiado estrecha, de ahí esta nueva pregunta.
:-(
¿Dónde se supone que debe buscar respuestas a esas preguntas si no es en este foro?
Pipeline<A,B>.connect(Pipeline<B,C>)
debe compilarse mientras Pipeline<A,B>.connect(Pipeline<C,D>)
que no debe compilarse: el tipo de salida de la primera etapa es incompatible con el tipo de entrada de la segunda etapa.