代码之家  ›  专栏  ›  技术社区  ›  wim

如何找到在coverage.py中从未执行过的代码,尽管有100%的覆盖率报告

  •  0
  • wim  · 技术社区  · 5 年前

    考虑以下代码:

    import math
    
    def dumb_sqrt(x):
        result = math.sqrt(x) if x >= 0 else math.sqrt(-x)*j
        return result
    
    
    def test_dumb_sqrt():
        assert dumb_sqrt(9.) == 3.
    

    测试可以这样执行:

    $ pip install pytest pytest-cov
    $ pytest test_thing.py --cov=test_thing --cov-report=html --cov-branch
    

    覆盖率报告将考虑所有线路100%覆盖,即使启用了分支覆盖:

    inline

    然而, 这段代码有个bug ,而你们这些眼光敏锐的人可能已经看到了。如果它进入“else”分支,将会有一个例外:

    NameError: global name 'j' is not defined
    

    修复bug很容易:更改undefined j 将名称转换为文字 1j 。添加另一个测试也很容易发现错误: assert dumb_sqrt(-9.) == 3j 这也不是这个问题要问的问题。我想知道如何 查找从未实际执行过的代码段 尽管有100%的代码覆盖率报告。

    使用条件表达式就是这样一个罪魁祸首,但Python在任何地方都可以缩短计算时间( x or y , x and y 还有其他示例)。

    优选地,上述第4行在报告中可以着色为黄色,类似于“if”行在一开始就避免使用条件表达式时的呈现方式:

    long

    coverage.py 支持这样的功能?如果是这样,您如何在新冠肺炎报告中启用“内联分支覆盖”?如果没有,是否有其他方法来识别您的测试套件从未实际执行过的“隐藏”代码?

    0 回复  |  直到 5 年前
        1
  •  3
  •   Martijn Pieters    5 年前

    不,coverage.py不处理表达式中的条件分支。这不仅影响Python条件表达式,还使用 and or 也会受到影响:

    # pretending, for the sake of illustration, that x will never be 0
    result = x >= 0 and math.sqrt(x) or math.sqrt(-x)*j
    

    Ned Batchelder,维护者 coverage.py ,称之为a 隐藏条件 ,在一个 article from 2007 covering this and other cases coverage.py can't handle .

    这个问题延伸到 if 声明也是!例如:

    if condition_a and (condition_b or condtion_c):
        do_foo()
    else:
        do_bar()
    

    如果 condition_b condition_a 是真的,你永远找不到拼写错误 condtion_c ,如果你完全依赖 converage.py ,因为不支持条件覆盖(更不用说更高级的概念了,比如 modified condition/decision coverage and multiple condition coverage .

    支持有条件覆盖的一个障碍是技术性的: coverage.py relies heavily on Python's built-in tracing support ,但直到最近,这只会让你跟踪每个 线 奈德 explored work-arounds for this issue .

    这并不是说阻止了另一个项目, instrumental 从提供条件/决策保险 无论如何 该项目使用AST重写和导入挂钩来添加额外的字节码,使其能够跟踪单个条件的结果,从而为您提供表达式“真值表”的概述。这种方法有一个巨大的缺点:它非常脆弱,经常需要更新新的Python版本。因此,该项目与Python 3.4决裂,尚未得到修复。

    Python 3.7 added support for tracing at the opcode level ,允许跟踪器分析每个字节码的效果,而无需诉诸AST黑客攻击。随着coverage.py 5.0达到稳定状态,它 appears that the project is considering adding support for condition coverage ,可能有赞助商支持开发。

    所以你现在的选择是:

    • 在Python 3.3中运行代码并使用工具
    • 修复工具可在较新的Python版本上运行
    • 等待coverage.py添加条件覆盖率
    • 帮助编写coverage.py的功能
    • 使用Python 3.7或更高版本,拼凑出你自己版本的instrumental方法 'opcode' 追踪模式。
        2
  •  -2
  •   dstromberg    5 年前

    如果cond-else为res2,则不要使用res1——它必须被视为一个单一的语句。如果你把它写成If/else,我认为coverage.py会做得更好。

    考虑使用类似pylint的东西,或者至少是pyflakes。我相信这些会自动检测到问题。