31

ヘッダーのみのC++ライブラリ(多くのテンプレートなど)では、GCovを使用してテストカバレッジをチェックします。ただし、未使用の関数はそもそもコンパイラによって生成されないため、すべてのヘッダーが100%カバーされていると報告されます。カバーされていない機能を手動で見つけるのは簡単ですが、継続的インテグレーションの目的を損ないます…</ p>

これを自動的に解決するにはどうすればよいですか?カバレッジメトリックとして「ラインヒット/LOC」を使用し、100%に到達しないようにする必要がありますか?

4

4 に答える 4

23

インライン化を制御する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
于 2013-11-05T15:46:52.157 に答える
2

また、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%として報告されますが、インスタンス化されていないテンプレート関数に関しては実際には当てはまりません。

于 2012-05-30T21:57:30.080 に答える
2

私もこの問題に遭遇しましたが、残念ながら、前述のさまざまなフラグを使用することはできませんでしたが、ヘッダーのみの関数を処理するときに、より正確なカバレッジ情報を生成する2つの方法を発見しました。

1つ目は、フラグを追加することです-fkeep-inline-functionshttps://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fkeep-inline-functions)。

これにより、私が求めていた結果が得られましたが、他のライブラリ(通常のC ++標準ライブラリでさえ)と統合しようとすると、いくつかの深刻な問題が発生しました。リンカによって削除されるべきであった特定の関数が削除されなかったため、リンクエラーが発生しました(たとえば、定義のない関数宣言)。

2番目のアプローチ(最終的に選択したアプローチ)は__attribute(used)__、GCCで使用してすべてのヘッダーAPI関数に注釈を付けることでした。ドキュメント(https://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html)には次のように記載されています。

使用済み

関数に付加されたこの属性は、関数が参照されていないように見える場合でも、関数のコードを発行する必要があることを意味します。

を使用し#defineてラップしたので、GCCを使用していて、カバレッジが有効になっている場合にのみオンにします。

#ifdef _MSC_VER
#define MY_API
#elif defined __GNUC__ && defined COVERAGE
#define MY_API __attribute__((__used__))
#endif // _MSC_VER ? __GNUC__ && COVERAGE

使用法は次のようになります。

MY_API void some_inline_function() {}

ある時点ですべてがどのように機能するようになったのかを書いてみます。これは、将来、これに近づいたら、ここからリンクします。

(注:-coverage -g -O0 -fno-inlineコンパイル時にも使用しました)

于 2019-08-04T09:28:14.903 に答える
1

この質問は、ヘッダーのみのライブラリのテストカバレッジを設定するのに非常に役立つことがわかったので、他の人に役立つことを期待して、次のことを学びました。

これらの回答で言及されているすべてのフラグがあっても、未使用のクラスメソッドが最適化されるという問題がまだありました。多くの実験の結果、clangソースベースのカバレッジ(これらのフラグ:)-fprofile-instr-generate -fcoverage-mappingにはすべてのクラスメソッドが含まれており、一般にカバレッジデータを取得するための最も信頼できる方法であることがわかりました。また、フラグを使用して-O0 -fno-inline -fno-elide-constructors、コードが最適化されるリスクをさらに減らします。

大規模なライブラリの場合、テンプレートのインスタンス化は依然として問題です。それらを明示的にインスタンス化することはすべてうまくいきますが、誰かがそれを忘れると、不正確なコードカバレッジメトリックが得られます。これを説明するためにコードカバレッジデータを自動的に調整する方法については、この質問に対する私の回答を参照してください。

于 2018-06-17T03:43:27.997 に答える