【问题标题】:Python coverage.py exclude_linesPython coverage.py exclude_lines
【发布时间】:2015-01-19 19:15:24
【问题描述】:

背景

我有几个使用coverage.py 的Django 项目,并且一直在尝试向我的.coveragerc 配置文件的exclude_lines 部分添加一些额外的表达式。问题是,即使使用适当的正则表达式在测试器中提取行,例如 http://www.pythonregex.comhttp://www.regexr.com,它也不会导致报告中忽略行。

我查看了docs 并查看了repository,但无法找出任何原因来解释为什么我的配置可能无法正常工作。从文档看来,我的配置与他们描述的完全一样。

我还尝试使用 django-nose 1.2 版,这是 PyPI 的最后一个版本,这将允许 exception injection 但无济于事,它似乎在确定 Django 视图和 Django REST 框架的覆盖范围方面存在一些问题API 端点至少在 1.7 版中。

我的尝试

我的配置如下:

[run]
branch = True
omit =
    */tests*
    */migrations/*
    *__init__.py*
    */settings/*
    *wsgi.py*
    *admin.py*

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
    pragma: no cover
    def __repr__
    if self.debug:
    raise AssertionError
    raise NotImplementedError
    (.*)except Exception as e:(.*)
    if 0:
    if __name__ == .__main__.:

我还在配置的报告部分尝试了以下组合来处理异常:

(.*)except Exception as e:
except Exception as e:
except Exception as e:(.*)

下面是我希望忽略的部分代码的函数示例:

def my_func():
    try:
        # Some logic
        return True
    except Exception as e:
        return defensive_exception(my_func.__name__, e, False)

在上面的示例中,根据文档,我希望 except Exception as e: 下的所有内容都被忽略,或者至少 except Exception as e 行本身被忽略。然而,情况似乎并非如此。如果有人对我的配置有什么问题或我需要做些什么有所了解,我将不胜感激。

【问题讨论】:

  • 问题是您现在需要排除多行但exclude_lines 旨在一次排除一行。它也不知道在哪里“结束”异常下的代码。最后,如果您这样做,您将无法了解异常处理代码中是否存在任何问题,因此最好编写测试以增加覆盖率。
  • 如前所述,如果它只排除一行但它甚至不排除 except Exception as e 行,我会很高兴。我有一些测试来测试每个使用它的实例的异常处理下面的代码,所以我不害怕它失败。此外,正如我所指出的,所有已知的异常都在 except Exception as e 处理程序之上处理并且已经过测试。至于不知道在哪里停止, (.*) 正则表达式在新的换行符处停止,因此至少应该忽略那一行。我还更新了问题以反映我使用 django-nose 的尝试。
  • 在回顾 django-nose 之后,似乎自上次发布以来已经有一些合并到 master 分支中,所以我会调查这些,但我仍然想了解我目前的配置存在的问题。
  • 我个人建议不要使用 Django-Nose,该项目几乎没有维护并且容易中断。我最近使用 pytest-django 将我的大部分项目切换到了 pytest。
  • @devonbleibtrey 我担心您的代码中有“异常除外”行,并且您想将它们排除在测试之外?这似乎是一个危险的模型。为什么要全面捕获异常,为什么不关心代码是否经过测试?

标签: python regex django code-coverage coverage.py


【解决方案1】:

你不需要匹配整行,所以最后不需要点星。这应该有效:

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
    pragma: no cover
    def __repr__
    if self.debug:
    raise AssertionError
    raise NotImplementedError
    except Exception as e:

这么说:这种编码风格让我非常关注。在你做的时候捕捉毯子异常是不好的风格,并且可以隐藏问题。那么您似乎并不关心该代码是否经过测试!

如果您需要像这样跨大量函数执行强大的异常处理,也许您想编写一个函数装饰器来包装函数调用。这将减少代码行数,并集中您的逻辑。然后,您也可以在一处处理覆盖问题。

【讨论】:

  • 喜欢装修师的推荐。我会过渡到那个。我已经尝试过配置文件的那个变体,但它似乎不起作用。根据我所做的搜索,似乎大多数人默认使用pragma: no cover,这在您的装饰器建议中可以正常工作。我一直在查看 repo 以找到一个可以证明功能的测试,但只能找到一些验证 cov.config.exclude_list 是否已填充。但我可能遗漏了一些东西。
  • 我看不出该正则表达式不起作用的任何原因。如果您需要我的帮助来调试它,请制作一个可重现的案例,然后通过电子邮件发送给我。
  • 再次感谢您的帮助。抱歉,当我最初提出这个问题时,我没有回复您的担忧。您完全正确,使用except Exception as e 是一个糟糕且有风险的实现。我们使用了那个实现,因为我们正在使用的一个包正在抛出未记录的异常,并且仍在弄清楚它们中的每一个是什么。话虽如此,我们过渡到了一个更好维护的包,并且在没有记录潜在异常时也开始为包做贡献,而不是采取上述懒惰、冒险的方法。感谢您的帮助!
【解决方案2】:

我总是使用pragma: no cover 来处理您在exclude_lines 中已有的内容。

def my_func():
    try:
        # Some logic
        return True
    except Exception as e:  # pragma: no cover
        return defensive_exception(my_func.__name__, e, False)

【讨论】:

  • 是的,这是一个选项,但我正在寻找一种方法,不必在我有这条线的任何地方添加 cmets。有人可能会认为这将是一项额外的检查,以确保只有经过测试的代码位于处理程序下方,但仍然没有回答为什么配置设置不起作用的问题。
猜你喜欢
  • 2018-06-04
  • 2016-07-30
  • 2012-01-13
  • 2016-09-15
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多