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 单元测试覆盖分析在使用块的文件上失败的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 7.0 和 7.1,代码覆盖打开,单元测试崩溃“无法合并以前的 GCDA 文件:损坏的弧标签”

如何:获取代码覆盖率数据

单元测试覆盖在 Sonarqube 中不可见

Xcode 7 代码覆盖率 - 无覆盖率数据

XCode 5 / ios7:缺少gcno文件

为什么?在单元测试覆盖范围内显示的类即使未在测试目标中添加