You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否有内置方式在CLI获取C#代码覆盖率输出?

在.NET命令行/CI环境中生成类似Simplecov Console的代码覆盖率报告

默认dotnet test生成的代码覆盖率结果确实仅为XML格式,但可以通过工具或自定义脚本实现类似Ruby Simplecov Console的格式化控制台输出,以下是两种可行方案:

方案一:使用ReportGenerator快速生成

ReportGenerator是.NET生态中成熟的覆盖率报告转换工具,支持直接输出格式化的控制台报告:

  1. 安装全局工具:
    dotnet tool install -g dotnet-reportgenerator-globaltool
    
  2. 执行测试并收集覆盖率数据:
    dotnet test --collect:"XPlat Code Coverage"
    
    该命令会在TestResults目录下生成Cobertura格式的XML覆盖率文件。
  3. 生成控制台格式报告:
    reportgenerator -reports:"TestResults/**/coverage.cobertura.xml" -targetdir:"coverage-report" -reporttypes:Console -sort:CoverageAscending -top:15
    
    参数说明:
    • -sort:CoverageAscending:按覆盖率从低到高排序
    • -top:15:仅显示覆盖率最低的15个文件(和你示例中的效果一致)
    • 还可通过-assemblyfilters、-filefilters等参数过滤不需要的文件

执行后就能在控制台看到包含整体覆盖率、文件覆盖率详情、缺失行范围的格式化报告。

方案二:Coverlet结合自定义脚本实现更定制化输出

如果需要完全复刻Simplecov的输出样式,可以用Coverlet生成覆盖率数据,再写脚本解析并格式化:

  1. 安装Coverlet测试包:
    dotnet add package coverlet.msbuild
    
  2. 生成Cobertura格式的覆盖率数据:
    dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
    
  3. 用Python脚本解析并生成表格(示例):
    安装依赖:
    pip install xmltodict tabulate
    
    创建脚本coverage_report.py:
    import xmltodict
    from tabulate import tabulate
    
    def format_missing_lines(line_list):
        if not line_list:
            return ""
        sorted_lines = sorted(map(int, line_list))
        ranges = []
        current_start = sorted_lines[0]
        current_end = sorted_lines[0]
        for line in sorted_lines[1:]:
            if line == current_end + 1:
                current_end = line
            else:
                ranges.append((current_start, current_end))
                current_start = line
                current_end = line
        ranges.append((current_start, current_end))
        return ', '.join([f"{s}-{e}" if s != e else str(s) for s, e in ranges])
    
    # 加载覆盖率XML文件
    with open('coverage.cobertura.xml', 'r') as f:
        coverage_data = xmltodict.parse(f.read())
    
    file_coverage_list = []
    total_covered = 0
    total_lines = 0
    
    # 遍历所有文件提取数据
    classes = coverage_data['coverage']['packages']['package']['classes']['class']
    # 处理单个文件的情况
    if not isinstance(classes, list):
        classes = [classes]
    
    for cls in classes:
        file_name = cls['@filename']
        covered = int(cls['lines']['@covered'])
        missed = int(cls['lines']['@missed'])
        total = covered + missed
        coverage_percent = (covered / total) * 100 if total > 0 else 0.0
    
        # 收集缺失行号
        missing_lines = []
        lines = cls['lines']['line']
        if isinstance(lines, list):
            for line in lines:
                if line['@covered'] == 'false':
                    missing_lines.append(line['@number'])
        else:
            if lines['@covered'] == 'false':
                missing_lines.append(lines['@number'])
    
        file_coverage_list.append({
            'coverage': f"{coverage_percent:.2f}%",
            'file': file_name,
            'lines': total,
            'missed': missed,
            'missing': format_missing_lines(missing_lines)
        })
    
        total_covered += covered
        total_lines += total
    
    # 输出整体覆盖率
    overall_coverage = (total_covered / total_lines) * 100 if total_lines > 0 else 0.0
    print(f"COVERAGE:  {overall_coverage:.2f}% -- {total_covered}/{total_lines} lines in {len(file_coverage_list)} files\n")
    
    # 排序并取最差15个文件
    sorted_files = sorted(file_coverage_list, key=lambda x: float(x['coverage'].replace('%', '')))
    show_count = min(15, len(sorted_files))
    print(f"showing bottom (worst) {show_count} of {len(file_coverage_list)} files")
    
    # 生成表格
    table_data = [[item['coverage'], item['file'], item['lines'], item['missed'], item['missing']] for item in sorted_files[:show_count]]
    headers = ["coverage", "file", "lines", "missed", "missing"]
    print(tabulate(table_data, headers=headers, tablefmt="grid"))
    
    # 统计100%覆盖率文件数
    full_coverage_count = len([f for f in file_coverage_list if float(f['coverage'].replace('%', '')) == 100.0])
    print(f"\n{full_coverage_count} file(s) with 100% coverage not shown")
    
  4. 运行脚本:
    python coverage_report.py
    
    即可得到和你示例几乎一致的控制台输出。

内容的提问来源于stack exchange,提问作者Caleb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 09:12:05