2008-10-21 8 views
8

Pruebas unitarias con C/C++: ¿Qué le enseñas a las personas que o no hicieron pruebas unitarias antes o vinieron de Java/Junit?Pruebas unitarias con C/C++: Lecciones, ¿qué recordar?

¿Cuál es la lección/cosa más importante para recordar/practicar desde su punto de vista que ahorra mucho tiempo o estrés (especialmente con respecto a C/C++)?

Respuesta

8
  1. Las pruebas unitarias deben ejecutarse automáticamente en cada registro (o, las pruebas unitarias que se escriben luego se olvidan no son pruebas unitarias).
  2. Antes de corregir un error, escriba una prueba de unidad para exponerlo (debe fallar). Luego arregla el error y regocíjate cuando la prueba se vuelva verde.
  3. Está bien sacrificar un poco de "belleza" de una clase para realizar pruebas más fáciles (como proporcionar métodos públicos que no deberían ser realmente públicos, pero que ayudan en sus pruebas/burlas).
+0

No estoy de acuerdo con 1. Todos los UT deben ejecutarse automáticamente durante la compilación nocturna, ya que generalmente toman mucho tiempo. Antes de cada check in debe ejecutar UT solo para su módulo. –

+2

3. También es incorrecto: haga que las clases de UT sean amigos y lo verán todo –

+1

m_pGladiator: "Un UT no es un UT por definición si se tarda más de 1/10 de segundo en ejecutarse", parafraseado de Working Effectively with Código heredado). Por lo tanto, estaría bien ejecutarlo automáticamente en cada commit. –

2

Me gustaría reformular ripper234 y añadir algunas reglas más:

  1. Cada módulo (por lo general del proyecto DLL) debe tener proyecto separado de UT. Todas las clases de UT deben ser amigos de todas las clases de DLL que necesitan para acceder a los métodos/miembros privados.
  2. Si desea cambiar el módulo, primero cambie el UT. Asegúrese de que tanto el DLL como su compilación UT, el enlace y el UT se ejecuten sin bloqueos y fallas antes del check in. No es necesario ejecutar todos los UT para todos los módulos antes de cada registro: esto es una pérdida de tiempo.
  3. Todos los UT deben reconstruirse automáticamente en la compilación nocturna junto con todas las DLL. Todos los UT y los módulos deben compilarse y vincularse durante la compilación.
  4. Todos los UT deben ejecutarse automáticamente después de que la compilación nocturna tenga éxito y los resultados se deben resumir.
  5. El resumen con todos los resultados de UT se debe enviar a los desarrolladores y, en caso de fallas o fallos, se deben corregir CUANTO ANTES.
1

Lección individual más importante: una prueba es mejor que ninguna prueba.

+0

A menos que la prueba esté rota, por supuesto, en cuyo caso está enviando en premisas falsas. –

+0

De hecho, creo que 1 prueba para una clase es más importante que 100 pruebas. La primera prueba es siempre la más difícil, especialmente con el código heredado, ya que te obliga a romper las dependencias alrededor de la clase para que puedas ponerla bajo prueba en primer lugar. –

1

Una carcasa de prueba unitaria solo debe probar una cosa.

Lo veo mucho más a menudo en C/C++ en comparación con C# y Java que los casos de prueba unitarios prueban flujos de trabajo completos.

Tal vez sea porque la mayoría de los marcos de C/C++ xUnit requieren varios pasos para registrar un caso de prueba, por lo que la tentación de agregar unas pocas líneas a un caso de prueba existente al agregar una nueva característica es mayor.

+0

Acepto, PERO, también me gusta ver 'pruebas unitarias' que prueban el objeto A conectado al objeto B, etc., en lugar de SÓLO pruebas que prueban el objeto B con burlas del objeto A. Me doy cuenta de que estas son más 'pruebas de integración ', pero también pueden ser muy útiles. –

+0

Nadie le prohíbe realizar pruebas de integración también. No deberías llamarlos pruebas unitarias, ni siquiera 'pruebas unitarias'. Llámelos pruebas de integración y no los mezcle con las pruebas de su unidad. –

2

En el caso de tratar con una base de código heredada sin pruebas, lo más probable es que empiece (como tenía que hacerlo) con pruebas funcionales que utilizan un marco de prueba unitario para la implementación. No se alarme: su código está tan interconectado que probablemente sea imposible escribir las pruebas unitarias correctas. No sea complaciente tampoco: una vez que las pruebas funcionales están en su lugar, necesita refactorizar para que las pruebas de unidades verdaderas sean posibles. ¡Tu código será mejor para eso!

3

Estoy en contra de todas estas recomendaciones para otorgar automáticamente amistad a clases de prueba ...

personalmente prefiero a centrarse en lo siguiente que me permita el acceso a la parte interna de una clase que necesito para probar:

  1. confiar en la interfaz pública de la clase cuando sea posible; a veces esto significa extender ligeramente la interfaz pública para permitir pruebas más fáciles. No pelee demasiado con estas extensiones, pero tampoco deje que manejen demasiado su diseño ...
  2. Considere agregar una interfaz de monitorización que también se puede usar con el código 'real' como código de prueba para habilitar el monitoreo de el código bajo prueba. (Todavía me sorprende la frecuencia con la que esta es una parte realmente buena del proceso de diseño).
  3. Considere proporcionar acceso a algunas partes de la clase a clases derivadas a través de una 'interfaz protegida' y obtenga una versión 'comprobable' de la clase en cuestión que luego puede ser instrumentada y probada.

En resumen, prefiero ver diseñado en puntos de prueba en lugar de una amistad general con una clase de prueba. Por supuesto, el primero es más difícil de hacer que el segundo, pero, en mi humilde opinión, los resultados en un mejor código Y mejores pruebas.

+0

@Len: buenos puntos. Normalmente intento mucho no tener que tener métodos públicos solo para las pruebas. Cuando resulta difícil probar algún código, entonces sus pruebas le indican que su diseño tiene problemas. Realmente, realmente quieres tener el mejor diseño. Pasa el tiempo y será más fácil. – quamrana

+1

Escucha tu código, huele tu código - ¡la amistad solo para las pruebas huele mal! – quamrana