2008-10-09 6 views
8

Estoy trabajando en una biblioteca C++ que (entre otras cosas) tiene funciones para leer archivos de configuración; y quiero agregar pruebas para esto. Hasta ahora, esto me ha llevado a crear muchos archivos de configuración válidos y no válidos, cada uno con solo unas pocas líneas que prueban una funcionalidad específica. Pero ahora es muy difícil de manejar, ya que hay muchos archivos y también muchas pequeñas aplicaciones de prueba de C++. De alguna manera, esto me parece incorrecto :-), ¿tienes alguna pista sobre cómo organizar todas estas pruebas, las aplicaciones de prueba y los datos de prueba?¿Cómo organizar las aplicaciones de prueba C++ y los archivos relacionados?

Nota: la API pública de la biblioteca no es fácilmente comprobable (requiere un archivo de configuración como parámetro). Los métodos jugosos y propensos a errores para leer e interpretar los valores de configuración son privados, ¿por lo que no veo una forma de probarlos directamente?

Entonces: ¿te quedarías con las pruebas contra archivos reales; y si es así, ¿cómo organizarías todos estos archivos y aplicaciones para que puedan ser mantenidos?

Respuesta

5

¿Quizás la biblioteca podría aceptar algún tipo de entrada de flujo, por lo que podría pasar un objeto tipo cadena y evitar todos los archivos de entrada? O, según el tipo de configuración, podría proporcionar las funciones "get/setAttribute()" directamente, publicitariamente, y modificar los parámetros. Si eso no es realmente un objetivo de diseño, entonces no importa. Las pruebas unitarias basadas en datos están mal vistas en algunos lugares, ¡pero definitivamente es mejor que nada! Yo probablemente diseñar el código como el siguiente:

project/ 
      src/ 
      tests/ 
       test1/ 
         input/ 
       test2 
         input/ 

En cada directorio TESTN que tendría un archivo CPP asociado a los archivos de configuración en el directorio de entrada.

Entonces, suponiendo que está utilizando una biblioteca de prueba de estilo xUnit (cppunit, googletest, unittest++, o lo que sea) puede agregar varias funciones testXXX() a una única clase de poner a prueba los grupos asociados de funcionalidad. De esta forma, podría recortar parte del problema de los lotes de programas pequeños al agrupar al menos algunas pruebas.

El único problema con esto es si la biblioteca espera que el archivo de configuración se llame algo específico o que se encuentre en un lugar específico. Ese no debería ser el caso, pero si lo hubiera, tendría que solucionarse copiando el archivo de prueba en la ubicación esperada.

Y no se preocupe por muchas pruebas que saturan su proyecto, si están ocultas en un directorio de pruebas, entonces no molestarán a nadie.

0

En algunas pruebas que he hecho, en realidad he usado el código de prueba para escribir los archivos de configuración y luego eliminarlos después de que la prueba haya utilizado el archivo. Pone un poco el código y no tengo idea si es una buena práctica, pero funcionó. Si usa boost, entonces su módulo de sistema de archivos es útil para crear directorios, navegar por directorios y eliminar los archivos.

0

Estoy de acuerdo con lo que dijo @Richard Quirk, pero también es posible que desee hacer de su clase de suite de prueba un amigo de la clase que está probando y probar sus funciones privadas.

1

Parte 1.

Como Richard sugirió, me gustaría echar un vistazo al marco CPPUnit prueba. Eso impulsará la ubicación de su marco de prueba hasta cierto punto.

Sus pruebas pueden realizarse en un directorio paralelo ubicado en un nivel alto, según el ejemplo de Richard, o en subdirectorios de prueba o directorios de prueba paralelos al área que desea probar.

De cualquier forma, sea coherente en la estructura del directorio en todo el proyecto. Especialmente en el caso de pruebas contenidas en un solo directorio de alto nivel.

No hay nada peor que tener que mantener un mapeo mental de código fuente en un lugar como:

/project/src/component_a/piece_2/this_bit 

y tener la prueba (s) situado en algún lugar como:

/project/test/the_first_components/connection_tests/test_a 

Y ¡He trabajado en proyectos donde alguien hizo eso!

¡Qué desperdicio de ciclos de wetware! 8-O Hable sobre la violación del concepto de Alexander de la calidad sin nombre.

Mucho mejor es tener sus pruebas constantemente ubicadas w.r.t. ubicación del código fuente bajo prueba:

/project/test/component_a/piece_2/this_bit/test_a 

Parte 2

En cuanto a los archivos de configuración de la API, hacer copias locales de una configuración de referencia en cada área de prueba local como parte del env prueba. configuración que se ejecuta antes de ejecutar una prueba. No rocíe copias de las configuraciones (o datos) a través de su árbol de prueba.

HTH.

aplausos,

Rob

Por cierto muy contento de verte pidiendo esto ahora, cuando establecimiento de las cosas!

0

Para cosas como esta siempre tengo una pequeña clase de utilidad que cargará una configuración en un búfer de memoria y de allí se alimenta a la clase de configuración actual. Esto significa que la fuente real no importa, podría ser un archivo o una base de datos. Para la prueba unitaria, está codificada en uno en una std :: string que luego se pasa a la clase para la prueba. Puede simular datos de currup! Pte3d fácilmente para probar rutas de falla.

Yo uso UnitTest++. Tengo las pruebas como parte del árbol src. Por lo tanto:

solution/project1/src <-- source code 
solution/project1/src/tests <-- unit test code 
solution/project2/src <-- source code 
solution/project2/src/tests <-- unit test code 
0

Asumiendo que usted tiene control sobre el diseño de la biblioteca, yo esperaría que usted sería capaz de refactorizar tal que separe las preocupaciones de archivo real de la lectura de interpretarlo como un archivo de configuración:

  1. FileReader clase lee el archivo y produce un flujo de entrada,
  2. ConfigFileInterpreter clase valida/interpreta etc. el contenido de la corriente de entrada

Ahora, para probar FileReader, necesitaría una cantidad muy pequeña de archivos reales (vacíos, binarios, texto sin formato, etc.) y para ConfigFileInterpreter usaría un stub de la clase FileReader que devuelve una secuencia de entrada para leer. Ahora puede preparar todas sus diversas situaciones de configuración como cadenas y no tendría que leer tantos archivos.

0

No encontrará un marco de pruebas unitarias peor que CppUnit. En serio, cualquiera que recomiende CppUnit realmente no ha echado un vistazo a ninguno de los marcos de la competencia.

Así que sí, vaya a una unidad de prueba de franework, pero no use CppUnit.

Cuestiones relacionadas