假设我有这段代码:
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。
我想过拥有一个全局函数,向量和一个宏 这个宏只是调用该函数,将源文件名和代码行作为参数传递,并且该函数将标记为“已检查”,方法是将向量插入宏传递的信息。
问题是我不会看到任何没有“检查”的路径 知道我该怎么做?如何在编译时“注册”一行代码,所以在运行时我可以看到它没有“检查”呢?
我希望我很清楚。
答案 0 :(得分:7)
通常,coverage工具包(例如gcov)随编译器提供。但请注意,他们通常只给你C0保险。即。
a ? b : c
也会被标记为已执行。因此,即使您的测试显示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;
}
};
也许有很多与此方法相关的问题,我还没有看到,并且使其在您的案例中具有实用性,正如其他人所指出的,使用静态代码分析工具对大多数情况来说是更好的解决方案。
编辑:
刚刚发现所提供的解决方案之前已在另一个背景下进行了讨论: