代码覆盖率(c ++代码执行路径)

时间:2010-06-01 00:29:25

标签: c++ path code-coverage execution

假设我有这段代码:

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和2。上面的代码中的3。

我想过拥有一个全局函数,向量和一个宏 这个宏只是调用该函数,将源文件名和代码行作为参数传递,并且该函数将标记为“已检查”,方法是将向量插入宏传递的信息。

问题是我不会看到任何没有“检查”的路径 知道我该怎么做?如何在编译时“注册”一行代码,所以在运行时我可以看到它没有“检查”呢?

我希望我很清楚。

6 个答案:

答案 0 :(得分:7)

通常,coverage工具包(例如gcov)随编译器提供。但请注意,他们通常只给你C0保险。即。

  • C0 - 每行至少执行一次。请注意,即使只使用了一个分支,a ? b : c也会被标记为已执行。
  • C1 - 每个分支至少执行一次。
  • C2 - 每个路径至少执行一次

因此,即使您的测试显示100%C0覆盖率,您也可能无法捕获代码中的每个路径 - 并且可能您没有时间去做(路径数量相对于分支呈指数增长)。但是,如果你有10%的C2或70%的C2(或0.1%的C2),那就很好了。

答案 1 :(得分:2)

您的编译器通常会提供一个实用程序来执行此类代码覆盖率分析。例如,GCC具有gcov实用程序。

答案 2 :(得分:2)

您需要代码覆盖程序(gcov,bullseye,dev partner)和单元测试(unittest ++,cppunit等)。你编写了测试该功能的测试。

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

在这种情况下,单元测试不只是检查完整性(尽管它们仍然存在),但它们也会测试覆盖率。

答案 3 :(得分:1)

尝试SD C++ TestCoverage获取VisualStudio兼容的测试覆盖率工具。我相信它实际上会告诉你关于 a?b:c 的测试覆盖率。

答案 4 :(得分:0)

您可以使用文件 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... */    
}

答案 5 :(得分:0)

  

问题是我不会看到任何没有“检查”的路径。

换句话说,这意味着您不仅要查找实际执行的代码点集,而且还要查找已经“标记”的代码点集合,以预期执行可能最终报告差异,我可能有一个非常dangerous的解决方案。它适用于MSVC 2010和2013。

方法是利用预编程开始初始化静态变量,但由于所有代码点都在函数中,因此,必须以某种方式将“静态anker点”放在那里,因此,{c ++的c ++特性{3}}必须克服。

这似乎可以通过模板类(X)与静态成员变量(progloc_)添加间接来强制执行每个模板参数的初始化,而参数又是一个传输所需信息的包装结构(_。 em> FILE ._“at line”_。 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_);

在ProgLocation中使用的S__LINE__ - 技巧 - ctor来自delayed initialization of static function variables

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

也许有很多与此方法相关的问题,我还没有看到,并且使其在您的案例中具有实用性,正如其他人所指出的,使用静态代码分析工具对大多数情况来说是更好的解决方案。

编辑:

刚刚发现所提供的解决方案之前已在另一个背景下进行了讨论:

here on SO