Получение полезных результатов GCov для библиотек только для заголовков - PullRequest
22 голосов
/ 12 марта 2012

Для моей библиотеки C ++ только для заголовков (много шаблонов и т. Д.) Я использую GCov для проверки покрытия тестами. Тем не менее, он сообщает о 100% -ном покрытии для всех заголовков, потому что неиспользуемые функции не генерируются компилятором. Обнаружение обнаруженных функций вручную легко, но не дает возможности непрерывной интеграции…

Как решить это автоматически? Должен ли я просто использовать «попадание строк / LOC» в качестве метрики покрытия и никогда больше не достигать 100%?

Ответы [ 3 ]

15 голосов
/ 05 ноября 2013

Помимо обычных флагов для GCC, управляющих встраиванием;

--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
2 голосов
/ 31 мая 2012

Я также использую GCov для проверки покрытия тестами (тесты, написанные с помощью среды Google Test), дополнительно я использую плагин интеграции Eclipse GCov или инструмент LCov, чтобы генерировать удобные для просмотра представления результатов покрытия тестами.Необработанный вывод GCov слишком сложен для использования: - (.

Если у вас есть библиотеки шаблонов только с заголовками, вам также необходимо оборудовать (используя флаг G ++ --coverage) ваши тестовые классы, которые создают экземпляры классов шаблонов и шаблона.функции-члены, чтобы увидеть разумные выходные данные GCov для них.

С помощью упомянутых инструментов легко обнаружить шаблонный код, который вообще не создавался в тестовых примерах, поскольку в нем НЕТ аннотаций.

Я настроил образец и скопировал вывод LCov в ссылку DropBox, которую вы можете проверить.

Пример кода (TemplateSampleTest.cpp инструментируется с использованием опции g ++ --coverage):

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);
}

См. Выходные данные покрытия кода, сгенерированные из lcov, здесь:

Покрытие TemplateSample.hpp

Предупреждение: статистика «Функции» отображается как 100%, что не совсем верно в отношении неинстанцированных функций шаблона.

0 голосов
/ 17 июня 2018

Поскольку я нашел этот вопрос очень полезным при настройке покрытия тестами для моей библиотеки только для заголовков, вот некоторые дополнительные вещи, которые я узнал в надежде, что они могут помочь другим:

Даже со всеми флагами, упомянутыми в этих ответах, у меня все еще были проблемы с оптимизацией неиспользуемых методов класса. После долгих экспериментов я обнаружил, что clang исходное покрытие (эти флаги: -fprofile-instr-generate -fcoverage-mapping) включает в себя все методы класса и в целом является наиболее надежным способом получения данных покрытия. Я также использую флаги: -O0 -fno-inline -fno-elide-constructors для дальнейшего снижения риска оптимизации кода.

Для большой библиотеки проблема создания экземпляра шаблона все еще остается проблемой. Явное их создание - это хорошо, но если кто-нибудь забудет об этом, вы получите неточные показатели покрытия кода. См. Мой ответ на этот вопрос , где описан подход к автоматической настройке данных покрытия кода с учетом этого.

...