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

如何使用coverage检测代码执行是否覆盖额外代码行

实现方法

你的思路完全可行,直接用coverage库自带的Python API就能实现全部逻辑,不需要手动解析.coverage二进制文件。

步骤1:生成基准覆盖率数据

先运行现有单元测试,拿到当前测试集已经覆盖的代码基线:

python -m coverage run -m pytest tests -vv

命令执行完成后会在当前目录生成.coverage文件,存储现有测试的覆盖信息。

步骤2:运行PDF遍历筛选脚本

下面的脚本可以直接实现你伪代码描述的逻辑,自动筛选出能提升覆盖率的PDF文件:

import os
from coverage import Coverage
from coverage.files import PathAliases
from PyPDF2 import PdfReader

# 替换成你存放PDF样本的目录路径
PDF_SAMPLE_DIR = "./path/to/your/pdf_files"
# 只统计PyPDF2本身的代码覆盖率,排除测试脚本、第三方依赖的干扰
COVERAGE_TARGET = ["PyPDF2"]

def get_text(path):
    reader = PdfReader(path)
    for page in reader.pages:
        text = page.extract_text()

if __name__ == "__main__":
    # 加载基准覆盖率数据
    base_cov = Coverage(source=COVERAGE_TARGET)
    base_cov.load()
    base_data = base_cov.get_data()
    path_alias = PathAliases()

    base_missing_lines = set()
    base_partial_lines = set()

    # 收集基准状态下未覆盖、部分覆盖的代码行
    for src_file in base_data.measured_files():
        norm_path = path_alias.canonical_filename(src_file)
        _, missing_lines, _ = base_cov.analysis(norm_path)
        base_missing_lines.update((norm_path, line_no) for line_no in missing_lines)
        # 收集分支覆盖不全的行(比如判断逻辑只走了True分支的情况)
        partial_arcs = base_data.partial_arcs(norm_path)
        for arc in partial_arcs:
            base_partial_lines.add((norm_path, arc[0]))
            base_partial_lines.add((norm_path, arc[1]))

    valuable_pdfs = []
    # 遍历目录下所有PDF文件
    for root, _, filenames in os.walk(PDF_SAMPLE_DIR):
        for filename in filenames:
            if not filename.lower().endswith(".pdf"):
                continue
            pdf_abs_path = os.path.abspath(os.path.join(root, filename))
            # 初始化临时覆盖率采集器,结果只存在内存里,不写入磁盘
            tmp_cov = Coverage(source=COVERAGE_TARGET, data_file=None)
            tmp_cov.start()
            try:
                get_text(pdf_abs_path)
            except Exception:
                # 触发异常的PDF往往能走到异常处理分支,同样有测试价值,不需要跳过
                pass
            tmp_cov.stop()

            # 提取当前PDF运行时覆盖到的代码行
            tmp_data = tmp_cov.get_data()
            current_covered = set()
            for src_file in tmp_data.measured_files():
                norm_path = path_alias.canonical_filename(src_file)
                covered_lines = tmp_data.lines(norm_path)
                if covered_lines:
                    current_covered.update((norm_path, line_no) for line_no in covered_lines)

            # 计算当前PDF带来的新增覆盖:命中原未覆盖行,或者命中原部分覆盖的行
            new_full_cover = base_missing_lines.intersection(current_covered)
            new_partial_hit = base_partial_lines.intersection(current_covered)
            total_new = new_full_cover.union(new_partial_hit)

            if total_new:
                valuable_pdfs.append({
                    "path": pdf_abs_path,
                    "new_line_count": len(total_new),
                    "new_lines": total_new
                })
            
            # 清空临时覆盖率数据,避免不同PDF的结果互相污染
            tmp_cov.erase()

    # 按新增覆盖的行数倒序排列,优先展示覆盖率贡献最高的文件
    valuable_pdfs.sort(key=lambda x: x["new_line_count"], reverse=True)
    for pdf in valuable_pdfs:
        print(f"有效样本: {pdf['path']},新增覆盖行数: {pdf['new_line_count']}")

实用优化建议

  • 脚本默认捕获所有PDF解析异常,遇到损坏、格式不规范的PDF不会中断遍历,这类文件通常能触发异常处理分支,本身就是很有价值的测试样本。
  • 覆盖率统计范围限定为PyPDF2源码,不会把遍历脚本、系统依赖的代码计入结果,避免统计误差。
  • 如果样本量特别大,可以加个终止判断:当所有原未覆盖的代码行都被命中过,直接停止遍历,不需要跑完所有文件,能节省大量时间。
  • 筛选出来的PDF可以按新增覆盖的行去重,避免加入内容重复、覆盖分支完全一致的样本,控制测试集体积。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:45:35