2009-06-19 18 views
6

Estoy configurando un conjunto de pruebas unitarias usando CppUnit pero estoy teniendo el problema de que ninguna de las pruebas se está ejecutando. El proyecto está dividido en varias bibliotecas pequeñas y planeé dividir las clases de prueba unitarias de la misma manera y luego vincularlas a todas en un solo programa de prueba. El problema es, entonces las clases de prueba están en sus propias bibliotecas, no consiguen incorporar en el programa principal prueba, a menos que explícitamente les llame, es decir, tengo que poner enVinculación en bibliotecas de prueba con CppUnit

runner.addTest(TestClass::suite());

de forma individual para cada prueba clase y no puede usar el método makeTests() de TestFactoryRegistry para obtener la lista de pruebas. Si simplemente los compilo todos juntos en el directorio superior, el método makeTests() funciona bien, pero no quiero tener todas las clases de prueba en una ubicación si puedo evitarlo.

La documentación CPPUnit da la siguiente pequeña pista

Vinculación problema cuando se utiliza ayudante macros?

Cuando se crea un proyecto y escribir sus unidad de pruebas, el trabajo se hace más fácil a través del uso de las llamados macros de ayuda: CPPUNIT_TEST_SUITE_NAMED_REGISTRATION, CPPUNIT_REGISTRY_ADD y CPPUNIT_REGISTRY_ADD_TO_DEFAULT. El problema es que si utiliza esos macros en el archivo de código fuente de una clase TestFixture (digamos MyTest como ejemplo ), y si se utiliza una línea como ésta

runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest() 

);

en su función main() en el archivo main.cpp, no habrá ejecución de prueba en absoluto!

La razón es simplemente que la etapa de enlace , uno de los pasos del proceso de construcción , no inserte la ficheros objeto (.obj o archivos .o) en la final ejecutable si no hay definido símbolo en su main.cpp.

De esta manera, el código objeto que contiene el AutoRegister estáticas variables de instanciación no es parte de el ejecutable final y no es capaz para insertar a sí mismo en el corredor en la función main().

usted tiene que crear un símbolo indefinido en main.cpp para que el archivo mytest.o se integra con main.o a la final ejecutable .

truco cometido por Michel Nolard

pero no dice cómo hacer este trabajo y estoy lo suficientemente densa como para no ser capaz de averiguarlo yo mismo o encontrar un ejemplo en línea.

Ahora podría hacer una prueba ejecutable por separado para cada biblioteca, y al final puedo ir por ese camino, pero quería intentar que esto funcionara primero, así que solo tuve que ejecutar un solo programa de prueba para probar el toda la cosa. ¿Alguna idea/ejemplo de cómo hacer que esto funcione?

Respuesta

1

Al agregar un símbolo indefinido a main, solo significa crear cualquier símbolo externo aleatorio para obligar al vinculador a buscar en las bibliotecas externas que contienen el código de prueba.

Por ejemplo, suponiendo dos bibliotecas de prueba Pedro y Pablo, en fredTestLib.cpp usted acaba de agregar esta línea:

int fredDummyInt = 0; // declare a unique symbol for the linker to resolve 

y en barneyTestLib.cpp, deberá añadir una línea similar:

int barneyDummyInt = 0; // a different unique symbol for the linker to resolve 

Puede compilar cada biblioteca por separado en diferentes pasos. En el programa de prueba principal, fuerza al vinculador a resolverlos. Así que añadir estas líneas a MAIN.CPP:

extern int fredDummyInt; 
extern int barneyDummyInt; 
... 
main() { 
    ... 
    fredDummyInt++; // give the linker some symbols to resolve 
    barneyDummyInt++; 
    ... 

La idea (de acuerdo a lo que el autor del truco anterior ya es decir) es que debido a que el enlazador ya está buscando fredTest.lib para fredDummyInt, también encontrará y resolver sus pruebas registradas automáticamente

Nota: ¡No he intentado esto para ver si funciona! Solo estoy respondiendo tu pregunta sobre externos.

Otro enfoque a considerar sería crear sus pruebas en DLL, y usar LoadLibrary() para ejecutarlas explícitamente. Para exceso, si usa MfcUi :: TestRunner, probablemente podría construir una pequeña GUI desplegable que le permita elegir la biblioteca para cargar, cargarla, luego mostrar las pruebas para ejecutarlas en esa biblioteca y luego ejecutarlas.

+0

Voy a probar esto esta noche. – dagorym

+0

Casi funcionó como yo quería. Al agregar esto, el sistema de registro recogió las pruebas en el archivo que contenía la variable externa pero no en todas las pruebas de la biblioteca. Hay alrededor de una docena de clases (cada una en su propio archivo) en la biblioteca y solo recogieron las pruebas para una en la que se encontraba la variable. Probablemente este sea el comportamiento correcto pero no me satisface en absoluto incluir cada clase individualmente. Tenía tanta esperanza de que esto funcionaría. – dagorym

+0

Bueno, estás tratando de obtener resultados "mágicos" sin código, y aunque te felicito por tu intento, en algún momento todos tenemos que escribir el código para realizar los trabajos. Estoy totalmente de acuerdo en que el código de auto-mantenimiento es el mejor tipo (el material en el que "simplemente funciona"), pero está buscando ir más allá del límite de un único módulo aquí, y ahí es donde tiene que ponerse complicado. ¿Cómo debe saber el vinculador cuándo dejar de traer nuevas bibliotecas? ¿Debería buscar todo tu disco duro? ¿Carpeta actual? Sub carpetas? Carpetas de ruta? Tiene que haber límites racionales, y más allá de eso, debe ser específico. –

0

La solución para este problema es bastante simple como statet before (pero puede que no sea muy elegante). Para cada TestFixture que se encuentra en una biblioteca externa que hay que añadir las siguientes dos líneas de código en el módulo principal

#include <CppUnitTestFixtureExample.h> 
CppUnitTestFixtureExample Test1; 

Se crea una variable ficticia sin usar que no se utiliza, sólo obliga al enlazador para enlazar el accesorio de prueba. Ahora el corredor de prueba que está ubicado en el módulo principal puede ejecutar la prueba.

0

Me doy cuenta de que esta publicación es bastante antigua, pero para cualquier otra persona que la encuentre: Una forma de abordar esto sin tener referencias en el código es instruir (forzar) al enlazador para que incluya toda la biblioteca estática en el binario Área de detalles disponibles en las páginas man ld gcc &, y este post abarca también: How to force gcc to link unreferenced, static C++ objects from a library

Por página hombre de LD, es importante tener en cuenta de manera explícita girando la opción de apagado (también se muestra en uno de los ejemplos anteriores).

Cuestiones relacionadas