XCode 5.1 单元测试覆盖分析在使用块的文件上失败
Posted
技术标签:
【中文标题】XCode 5.1 单元测试覆盖分析在使用块的文件上失败【英文标题】:XCode 5.1 Unit Test Coverage Analysis Fails On Files Using Blocks 【发布时间】:2014-04-16 03:03:25 【问题描述】:今天我的任务是在我们的代码库中添加单元测试覆盖率分析。今天也是 ios 7.1 与 XCode 5.1 一起发布的日子。来自发行说明:
重新实现了用于代码覆盖率测试的 gcov 工具。新版本使用来自 LLVM 项目的 llvm-cov 工具。它在功能上等同于旧版本的所有重要特性。 Xcode 中 gcov 的位置也移动了,使用 xcrun 调用它。如果您发现问题,请提交错误报告。对于此版本,您仍然可以使用来自 GCC 的旧版本 gcov,它以 gcov-4.2 的形式提供。 11919694 更新
我只是在关注了几个instructionalblogposts之后才意识到这一点,正确设置了我的环境-在测试时在模拟器的构建文件夹中生成.gcda/.gcno文件-并使用报告生成工具@987654324 @尝试将它们解析成报告。 (这是一个 ./getcov 脚本,它收集您的环境变量以传递给 lcov-1.10 脚本以生成报告)
第一个障碍是新捆绑的gcov
程序不支持-v
参数来获取版本,这是lcov
初始化的第一步。似乎已经不是初学者了,但是阅读了上面的发行说明,我修改了 lcov
脚本以使用旧的 gcov-4.2
版本并解决了这个问题。
但是,lcov
在处理我的覆盖数据文件时很早就出错了。这会生成一个报告,其中可能包含我项目中按字母顺序排列的前 10 个左右的文件。不是特别有用。错误输出也很小且无用:
geninfo: 错误: (build_artifacts)/(class_that_errored).gcda 的 GCOV 失败!
我修改了lcov
脚本以打印它得到的错误(不幸的是,它只产生了11
,在 gcov(-io).c 代码中找不到任何引用)并继续操作而不是退出,所以我在报告中留下了更多的文件,但我的源文件中可能仍有 85% 的错误如上所示。
在报告中成功结束的文件和引发错误的文件之间,我能辨别的唯一模式是任何使用内联块声明的文件都失败了。没有以任何方式通过使用块的文件,并且我检查过的所有失败的文件都包含块。奇怪。
然后我发现我可以打开 CoverStory 中的各个 .gcda 文件,包括在 lcov
脚本中出错的文件。在覆盖率报告下方的消息窗口中,所有出错的文件都有警告消息:
(class_that_errored).gcno:'__copy_helper_block_' 没有行
(class_that_errored).gcno:'__destroy_helper_block_' 没有行
此时我最好的假设是新的 XCode 5.1 正在生成 .gcda 文件,而旧的 gcov-4.2
程序不具备处理块声明的能力。
但是我已经用尽了所有我能想到的尝试,所以我在这里询问是否有人有我错过的知识,或者有任何想法来进一步调试工作。或者,如果有人在今天的 XCode 5.1 更新后使用新的 gcov
成功测量了测试覆盖率,我也很想听听您必须做出的任何更改。
【问题讨论】:
也需要这个问题的答案 - 我在 Xcode 5.1 上遇到了完全相同的问题。我们的代码覆盖率从 16,800 行的 52% 下降到 12,000 行的 57% 左右。我们还发现提到的两条块线存在问题。 我正在使用 gcovr(可在此处获得:pypi.python.org/pypi/gcovr)来解释覆盖结果,这比 CoverStory 得到的答案更不准确。它无法处理的 GCDA 文件会生成“MySourceFile.m:没有这样的文件或目录”的错误。奇怪的是,直接在有问题的 GCDA 文件上调用 gcov 似乎会创建适当的文件。如果有人可以对此有所了解,请在下面创建一个答案! 此外,与源/线路测量相反,功能测量似乎不存在。在 Xcode 5.1 之前,lcov 能够同时测量两者。 @Endersstocker 不确定为什么会发生这种变化,但是如果您明确指示 lcov 使用 --derive-func-data 参数导出数据,则会恢复原始行为。我刚刚将参数添加到 Jon Reid 的 getcov shell 脚本中的 gather_coverage() 函数中。 @jstevenco 我已经尝试将它添加到gather_coverage() 函数中 - 不幸的是,这似乎无法解决问题。使用块的类似乎仍然没有得到覆盖。 【参考方案1】:问题出在 LCOV 1.10 geninfo 脚本中。它测试当前版本的 gcov。它通过解析版本字符串来做到这一点。由于 gcov 现在指向 llvm-cov,版本字符串解析不正确。
解决方法是修改geninfo的get_gcov_version()子程序。在 1868 行中,将 -v
更改为 --version
。然后将 1874 行替换为:
if ($version_string =~ m/LLVM/)
info("Found llvm-cov\n");
$result = 0x40201;
elsif ($version_string =~ /(\d+)\.(\d+)(\.(\d+))?/)
修改后的子程序应如下所示:
sub get_gcov_version()
local *HANDLE;
my $version_string;
my $result;
open(GCOV_PIPE, "-|", "$gcov_tool --version")
or die("ERROR: cannot retrieve gcov version!\n");
$version_string = <GCOV_PIPE>;
close(GCOV_PIPE);
$result = 0;
if ($version_string =~ m/LLVM/)
info("Found llvm-cov\n");
$result = 0x40201;
elsif ($version_string =~ /(\d+)\.(\d+)(\.(\d+))?/)
if (defined($4))
info("Found gcov version: $1.$2.$4\n");
$result = $1 << 16 | $2 << 8 | $4;
else
info("Found gcov version: $1.$2\n");
$result = $1 << 16 | $2 << 8;
return ($result, $version_string);
注意:确保--gcov-tool
没有设置为gcov-4.2
。
【讨论】:
已经尝试像上面那样切换到使用 XcodeCoverage 工具,它似乎比使用 Xcode 5.1 的 gcovr 更糟糕。使用我当前的设置,它甚至根本无法生成任何报告... @DavidDoyle:getcov 是返回错误还是只收到一个空白报告? @DavidDoyle:你能告诉我它们是什么吗? 太多了,无法一口气发完,所以我将它们分成三个部分: 总结一下:这似乎确实解决了 lcov 的问题,但是看到的原始问题(任何带有块的内容都不会出现在覆盖率报告中)仍然存在......跨度> 【参考方案2】:我没有修改geninfo
,而是创建了一个llvm-cov-wrapper
脚本并使用了lcov 的--gcov-tool
命令行选项:
#!/bin/bash
# llvm-cov wrapper to make it behave more like gcov
if [ "$1" = "-v" ]; then
echo "llvm-cov-wrapper 4.2.1"
exit 0
else
/usr/bin/gcov $*
fi
【讨论】:
它说必须指定至少 1 个位置参数:【参考方案3】:实际上,我注意到 lcov 正在使用 -b 选项调用 gcov,而 gcov-4.2 将在此选项上崩溃(引发分段错误)。如果我从 getinfo 中删除 -b 选项,那么即使它仍然显示一些错误信息,仍然可以生成 gcov 文件。
这可能就是为什么封面故事仍然可以提供报道输出的原因。所以我想解决方法是从lcov中删除-b选项。并且也如您所建议的,忽略 getinfo 中的错误
【讨论】:
【参考方案4】:对于此线程的新手,请注意 lcov-1.11 已发布。这消除了gcov -v
兼容性的问题。但是,我使用的是 XCode 6.1,但某些文件仍然出现错误。
geninfo: WARNING: /Users/XXX/MyFile.gcno: found unrecognized record format - skipping
请注意,您可以添加--ignore-errors graph
来跳过这些错误,但问题并没有真正解决。
【讨论】:
以上是关于XCode 5.1 单元测试覆盖分析在使用块的文件上失败的主要内容,如果未能解决你的问题,请参考以下文章