c++ gcc gcov

c++ - Obtención de resultados útiles de GCov para bibliotecas de solo encabezado



gcc (3)

Aparte de las banderas habituales para GCC que controlan la alineación;

--coverage -fno-inline -fno-inline-small-functions -fno-default-inline

Puede crear una instancia de sus clases de plantilla en la parte superior de los archivos de prueba de su unidad;

template class std::map<std::string, std::string>;

Esto generará código para cada método en esa clase de plantilla haciendo que las herramientas de cobertura funcionen perfectamente.

Además, asegúrese de inicializar sus archivos * .gcno (así que para lcov)

lcov -c -i -b ${ROOT} -d . -o Coverage.baseline <run your tests here> lcov -c -d . -b ${ROOT} -o Coverage.out lcov -a Coverage.baseline -a Coverage.out -o Coverage.combined genhtml Coverage.combined -o HTML

Para mi biblioteca de C ++ solo para el encabezado (muchas plantillas, etc.) uso GCov para verificar la cobertura de la prueba. Sin embargo, informa de una cobertura del 100% para todos los encabezados porque las funciones no utilizadas no son generadas por el compilador en primer lugar. La localización manual de funciones no cubiertas es fácil, pero elimina el propósito de la integración continua ...

¿Cómo se resuelve esto automáticamente? ¿Debería usar "line hit / LOC" como métrica de cobertura y nunca volver a alcanzar el 100%?


Desde que encontré esta pregunta muy útil para configurar la cobertura de prueba para mi biblioteca de solo encabezado, aquí hay algunas cosas adicionales que aprendí con la esperanza de que puedan ayudar a otros:

Incluso con todas las marcas mencionadas en estas respuestas, seguía teniendo problemas con la optimización de los métodos de clase no utilizados. Después de mucha experimentación, descubrí que la cobertura basada en el origen del -fprofile-instr-generate -fcoverage-mapping (estas -fprofile-instr-generate -fcoverage-mapping : -fprofile-instr-generate -fcoverage-mapping ) incluye todos los métodos de clase y en general es la forma más confiable de obtener datos de cobertura. También utilizo los indicadores: -O0 -fno-inline -fno-elide-constructors para reducir aún más el riesgo de que el código se optimice.

Para una biblioteca grande, la creación de instancias de plantilla sigue siendo un problema. Hacer una instancia explícita de ellos es bueno y bueno, pero si alguien se olvida de hacerlo, obtendrás métricas de cobertura de código inexactas. Vea mi respuesta a esta pregunta para un enfoque para ajustar automáticamente los datos de cobertura de código para tener en cuenta esto.


También estoy usando GCov para verificar la cobertura de la prueba (Pruebas escritas con el marco de Google Test), además, uso el complemento de integración Eclipse GCov o la herramienta LCov para generar vistas fáciles de inspeccionar de los resultados de la cobertura de la prueba. La salida en bruto de GCov es demasiado difícil de usar :-(.

Si tiene bibliotecas de plantillas de solo encabezado, también necesita instrumentar (usando el indicador G ++ --coverage) sus clases de prueba que ejemplifican las clases de plantilla y las funciones de miembro de plantilla para ver resultados GCov razonables para estas.

Con las herramientas mencionadas, es fácil detectar el código de la plantilla que no se creó una instancia de los casos de prueba, ya que NO tiene anotaciones.

He configurado una muestra y copiado la salida LCov a un enlace de DropBox que puede inspeccionar.

Código de ejemplo (TemplateSampleTest.cpp se --coverage mediante la opción de --coverage g ++):

TemplateSample.hpp

template<typename T> class TemplateSample { public: enum CodePath { Path1 , Path2 , Path3 , }; TemplateSample(const T& value) : data(value) { } int doSomething(CodePath path) { switch(path) { case Path1: return 1; case Path2: return 2; case Path3: return 3; default: return 0; } return -1; } template<typename U> U& returnRefParam(U& refParam) { instantiatedCode(); return refParam; } template<typename U, typename R> R doSomethingElse(const U& param) { return static_cast<R>(data); } private: void instantiatedCode() { int x = 5; x = x * 10; } void neverInstantiatedCode() { int x = 5; x = x * 10; } T data; };

TemplateSampleTest.cpp

#include <string> #include "gtest/gtest.h" #include "TemplateSample.hpp" class TemplateSampleTest : public ::testing::Test { public: TemplateSampleTest() : templateSample(5) { } protected: TemplateSample<int> templateSample; private: }; TEST_F(TemplateSampleTest,doSomethingPath1) { EXPECT_EQ(1,templateSample.doSomething(TemplateSample<int>::Path1)); } TEST_F(TemplateSampleTest,doSomethingPath2) { EXPECT_EQ(2,templateSample.doSomething(TemplateSample<int>::Path2)); } TEST_F(TemplateSampleTest,returnRefParam) { std::string stringValue = "Hello"; EXPECT_EQ(stringValue,templateSample.returnRefParam(stringValue)); } TEST_F(TemplateSampleTest,doSomethingElse) { std::string stringValue = "Hello"; long value = templateSample.doSomethingElse<std::string,long>(stringValue); EXPECT_EQ(5,value); }

Vea la salida de cobertura de código generada desde lcov aquí:

TemplateSample.hpp de cobertura

Advertencia: las estadísticas de ''Funciones'' se informan como 100%, lo que no es realmente cierto con respecto a las funciones de plantilla no instanciadas.