10

私がこのコードを持っているとしましょう:

int function(bool b)
{
    // execution path 1
    int ret = 0;
    if(b)
    {
        // execution path 2
        ret = 55;
    }
    else
    {
        // execution path 3
        ret = 120;
    }
    return ret;
}

コードが可能なパス、つまり上記のコードの実行パス1、2、3に確実に入るようにするために、ある種のメカニズムが必要です。

グローバル関数、ベクトル、マクロを考えました。
このマクロは単にその関数を呼び出し、パラメーターとしてソースファイル名とコード行を渡します。その関数は、マクロが渡した情報をベクターに挿入することにより、それを「チェック済み」としてマークします。

問題は、「チェック」されなかったパスについては何も表示されないことです。
どうすればこれを行うことができますか?コンパイル時にコード行を「登録」する方法。実行時に、まだ「チェック」されていないことがわかりますか?

はっきりしているといいのですが。

4

6 に答える 6

8

通常、カバレッジユーティリティ(gcovなど)はコンパイラに付属しています。ただし、通常はC0カバレッジのみが提供されることに注意してください。つまり

  • C0-すべての行が少なくとも1回実行されます。a ? b : cブランチが1つしか使用されていない場合でも、実行済みとしてマークされていることに注意してください。
  • C1-すべてのブランチが少なくとも1回実行されます。
  • C2-すべてのパスが少なくとも1回実行されます

したがって、テストで100%のC0カバレッジが示された場合でも、コード内のすべてのパスをキャッチできるとは限りません。おそらく、それを実行する時間がありません(パスの数はブランチに対して指数関数的に増加します)。ただし、10%のC2または70%のC2(または0.1%のC2)があるかどうかを知っておくとよいでしょう。

于 2010-06-01T00:53:05.273 に答える
2

多くの場合、この種のコードカバレッジ分析を行うためのユーティリティがコンパイラに付属しています。たとえば、GCCにはgcovユーティリティがあります。

于 2010-06-01T00:40:29.497 に答える
2

コードカバレッジプログラム(gcov、ブルズアイ、開発パートナー)とユニットテスト(unittest ++、cppunitなど)が必要です。その機能をテストするテストを作成します。

TEST( UnitTestFunction )
{
    CHECK( function(true) == 55 );
    CHECK( function(false) == 120 );
}

次に、この場合の単体テストは、整合性をチェックするだけでなく(まだそうですが)、カバレッジもテストします。

于 2010-06-01T09:28:36.713 に答える
1

VisualStudio互換のテストカバレッジツールについては、SD C++TestCoverageをお試しください。実際には、a?b:cのテストカバレッジについても教えてくれると思います。

于 2010-06-04T12:47:47.177 に答える
1

問題は、「チェック」されなかったパスについては何も表示されないことです。

つまり、実際に実行されるコードポイントのセットだけでなく、最終的に違いを報告するために実行されることが期待されるように何らかの形で「マーク」されたコードポイントのセットも探しているということです。私は非常に危険な解決策を持っているかもしれません。それはMSVC2010と2013で私のために働きます。

アプローチは静的変数のプログラム開始前の初期化を利用することですが、すべてのコードポイントが関数内にあるため、「静的アンカーポイント」を何らかの方法でそこに配置する必要があります。したがって、静的変数の初期化を遅らせるc++機能関数変数を克服する必要があります。

これは、静的メンバー変数(progloc_)を使用してテンプレートクラス(X)を介して間接参照を追加し、必要な情報(_。FILE ._"を転送するラッパー構造体であるテンプレートパラメーターごとの初期化を強制することで可能になるようです。行" _。LINE._)で。

これをまとめると、これを実現するための最も重要なコードは次のようになります。

template <class T> class X {
public:
    static T progloc_;
};
template <class T> T X<T>::progloc_;

#define TRACE_CODE_POINT \
    struct ProgLocation { \
    public: \
        std::string loc_; \
        ProgLocation() : loc_(std::string(__FILE__ " at line " S__LINE__)) \
        { \
            TestFw::CodePoints::Test::imHere(loc_); \
        } \
    }; \
    TestFw::CodePoints::X<ProgLocation> dummy; \
    TestFw::CodePoints::Test::iGotCalled(dummy.progloc_.loc_);

S__LINE__-ProgLocationで使用されるトリック-ctorはここからSOにあります。

#define S(x) #x
#define S_(x) S(x)
#define S__LINE__ S_(__LINE__)

追跡するには、以下を使用します。

class Test
{
private:
    typedef std::set<std::string> TFuncs;
    static TFuncs registeredFunctions;
    static TFuncs calledFunctions;
public:
    static int imHere(const std::string fileAndLine)
    {
        assert(registeredFunctions.find(fileAndLine) == registeredFunctions.end());
        registeredFunctions.insert(fileAndLine);
        return 0;
    }
    static void iGotCalled(const std::string fileAndLine)
    {
        if (calledFunctions.find(fileAndLine) == calledFunctions.end())
            calledFunctions.insert(fileAndLine);
    }
    static void report()
    {
        for (TFuncs::const_iterator rfIt = registeredFunctions.begin(); rfIt != registeredFunctions.end(); ++rfIt)
            if (calledFunctions.find(*rfIt) == calledFunctions.end())
                std::cout << (*rfIt) << " didn't get called" << std::endl;
    }
};

たぶん、このアプローチに関連する多くの問題がありますが、私はまだ見ていませんが、あなたのケースでは実用的ではありません。他の人が指摘しているように、静的コード分析ツールを使用することは、ほとんどの状況でより良い解決策です。

編集:

提供されたソリューションが以前に別のコンテキストで説明されていることがわかりました。

non-deferred-static-member-initialization-for-templates-in-gcc

于 2013-12-20T00:22:22.013 に答える
0

FILEおよびLINEプリプロセッサディレクティブを使用できます。

#define TRACE(msg) MyTraceNotify(msg,__FILE__,__LINE__)

追跡したい場所のコードにカスタムメッセージとともにTRACE(msg)マクロを挿入し、MyTraceNotify関数を記述します。

void MyTraceNotify(const char *msg, const char *filename, ULONG line)
{
    /* Put your code here... */    
}
于 2010-06-01T02:13:47.267 に答える