Получив полезные результаты GCov для только заголовков библиотек
для моей только заголовочной библиотеки C++ (много шаблонов и т. д.) Я использую GCov для проверки тестового покрытия. Однако он сообщает 100% покрытие для всех заголовков, потому что неиспользуемые функции не генерируются компилятором в первую очередь. Ручное обнаружение непокрытых функций легко, но побеждает цель непрерывной интеграции...
Как это решить автоматически? Должен ли я просто использовать "линии hit / LOC" в качестве метрики покрытия и просто никогда не достигать 100% снова?
3 ответов
отдельно от обычных флагов к GCC контролируя inlining;
--coverage -fno-inline -fno-inline-small-functions -fno-default-inline
вы можете создавать экземпляры классов шаблонов в верхней части файлов модульных тестов;
template class std::map<std::string, std::string>;
Это создаст код для каждого метода в этом классе шаблонов, что сделает инструменты покрытия работать отлично.
кроме того, убедитесь, что вы запустить ваш *.gcno файлы (так для 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
Я также использую GCov для проверки тестового покрытия (тесты, написанные с помощью Google Test framework), кроме того, я использую плагин интеграции Eclipse GCov или инструмент LCov для создания простых для проверки представлений результатов тестового покрытия. Выход raw GCov слишком сложен для использования : - (.
Если у вас есть только заголовочные библиотеки шаблонов, вам также нужно использовать (используя флаг G++ --coverage) ваши классы тестирования, которые создают экземпляры классов шаблонов и функций-членов шаблона, чтобы увидеть разумные выходы GCov для этих.
С помощью упомянутых инструментов легко определить код шаблона, который не был создан с тестовыми случаями вообще, так как он не имеет аннотаций.
Я настроил образец и скопировал вывод LCov в ссылку DropBox, которую вы можете проверить.
пример кода (TemplateSampleTest.cpp инструментируется с помощью g++ --coverage
вариант):
TemplateSample.ГЭС
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);
}
см. выход покрытия кода, сгенерированный из lcov здесь:
нюанс: "функции" статистика отображается как 100%, что не совсем верно в отношении не инстанцировать шаблон функции.
поскольку я нашел этот вопрос очень полезным при настройке тестового покрытия для моей библиотеки только для заголовков, вот некоторые дополнительные вещи, которые я узнал в надежде, что они могут помочь другим:
даже со всеми флагами, упомянутыми в этих ответах, у меня все еще были проблемы с оптимизацией неиспользуемых методов класса. После долгих экспериментов я обнаружил, что clang источник освещения (эти флаги: -fprofile-instr-generate -fcoverage-mapping
) включает в себя все методы класса и в целом является наиболее надежным способ получения данных покрытия. Я также использую флаги:-O0 -fno-inline -fno-elide-constructors
для дальнейшего снижения риска оптимизации кода.
для большой библиотеки создание экземпляра шаблона по-прежнему является проблемой. Явное их создание-это хорошо, но если кто-нибудь когда-нибудь забудет, вы получите неточные показатели покрытия кода. См. мой ответ на этот вопрос для подхода к автоматической настройке данных покрытия кода для учета этого.