【问题标题】:How to properly use coverage.py in Python?如何在 Python 中正确使用 coverage.py?
【发布时间】:2016-07-30 18:03:27
【问题描述】:

我刚开始使用Coverage.py 模块,所以决定做一个简单的测试来检查它是如何工作的。

Sample.py

def sum(num1, num2):
    return num1 + num2


def sum_only_positive(num1, num2):
    if num1 > 0 and num2 > 0:
        return num1 + num2
    else:
        return None

test.py

from sample import sum, sum_only_positive

def test_sum():
    assert sum(5, 5) == 10

def test_sum_positive_ok():
    assert sum_only_positive(2, 2) == 4

def test_sum_positive_fail():
    assert sum_only_positive(-1, 2) is None

如您所见,我的所有代码都包含测试,py.test 表示所有代码都通过了。我希望 Coverage.py 显示 100% 的覆盖率。嗯,没有。

好吧,Coverage.py 可能看不到 test.py 文件,所以我将测试函数复制到 sample.py 文件并再次运行 Coverage:

然后我添加了这段代码:

if __name__ == "__main__":
    print(sum(2, 4))
    print(sum_only_positive(2, 4))
    print(sum_only_positive(-1, 3))

并删除了所有测试功能。之后,Coverage.py 显示 100%:

为什么会这样? Coverage.py 不应该显示代码测试覆盖率,而不仅仅是执行覆盖率吗?我已经阅读了 Coverage.py 的官方 F.A.Q.,但找不到解决方案。
由于很多 SO 用户都熟悉代码测试和代码覆盖率,希望您能告诉我,我错在哪里了。

我在这里只有一个想法:Coverage.py 可能只是观察哪些代码行没有执行,所以我应该为这些行编写测试。但是有些行已经执行但没有被测试覆盖,所以 Coverage.py 在这里会失败。

【问题讨论】:

  • 如何调用coverage/pytest?
  • @Rogalski pytest:python -m py.test test.py 和覆盖范围:python -m coverage run sample.py(在 Windows 上)
  • 它没有显示 100%,它显示的行与未覆盖的行相同……它仍然对我不起作用。我复制粘贴了你的代码,并确保我有 py.test 和 coverage.py 和 pip。我在命令行和 intellij 中看到相同,请 LMK。

标签: python unit-testing python-3.x coverage.py


【解决方案1】:

Coverage 会查找 .coverage 文件来读取并为您生成该报告。 Py.test 本身不会创建一个。您需要 py.test 插件进行覆盖:

pip install pytest-cov

如果您已经拥有它,那么您可以像这样同时运行两者:

py.test test.py --cov=sample.py

这意味着运行测试模块test.py 并在sample.py 上记录/显示覆盖率报告。

如果您需要进行多次测试运行并累积它们记录的覆盖率然后显示最终报告,您可以这样运行:

py.test test.py --cov=sample.py --cov-report=
py.test test.py --cov=sample2.py --cov-report=
py.test test.py --cov=sample3.py --cov-report=

这意味着运行测试模块 test.py 并(仅)记录 sample.py 的覆盖率 - 不显示报告。

现在您可以单独运行覆盖命令以获得完整报告:

coverage report -m

上面的命令只是根据以前测试运行的累积 .coverage 数据文件显示格式化的覆盖率报告。 -m 表示缺少显示行,即测试未涵盖的行:

Name        Stmts   Miss  Cover   Missing
-----------------------------------------
sample.py       6      0   100%  

Coverage 支持更多开关,例如 --include--omit,以使用路径模式包含/排除文件。欲了解更多信息,请查看他们的文档:https://coverage.readthedocs.io/en/6.0.2/source.html?highlight=reporting#reporting

【讨论】:

  • 如果要检查的文件是测试中导入的包中的子模块,则不起作用。无论我在 --cov=<> 指定什么 - 只是文件名、相对或绝对路径 - 我都会收到“错误:无法生成报告:没有要报告的数据。”
  • "asterisk/mydir/asterisk" 适用于省略。我会写 * 作为星号,但它会变成粗体。
  • 使用--branch 也可以添加分支覆盖率。
  • 如果额外的依赖不值得,你也可以使用coverage run --source=<module-name> -m pytest <test-location> 而不是py.test test.py --cov=sample.py
  • ERROR: usage: py.test [options] [file_or_dir] [file_or_dir] [...] py.test: error: unrecognized arguments: --cov=test.py
【解决方案2】:

在每个测试文件夹中添加__init__.py 可以解决原始问题并显示正确的覆盖范围。

【讨论】:

    【解决方案3】:

    以下命令对我有用:

    coverage run --source=sample -m pytest test.py
    
    coverage report -m
    

    【讨论】:

    • 提醒其他任何遇到此问题的人。从 2021 和 Coverage v5.3.1 开始,这是推荐的方法。
    【解决方案4】:

    在您的实验中解析有点困难,而且您还没有包含用于每个实验的命令行。但是:如果您使用以下方式运行测试:

    python -m py.test test.py
    

    然后你可以在coverage.py下运行它们:

    coverage run -m py.test test.py
    

    【讨论】:

    • 顺便说一句,我在第二条评论的帖子下包含了用于运行测试和覆盖的命令:pytest:python -m py.test test.py 和覆盖:python -m coverage run sample.py(在 Windows 上)。我看到您的第二个命令与我的不同,请检查一下,谢谢!
    • 也许这里的问题是一个基本的误解:你不应该运行测试,然后覆盖。您应该使用覆盖来运行测试(我推荐的方式),或者在测试运行期间启用覆盖(例如使用测试运行器的覆盖插件)。
    • 对我不起作用:( coverage -m -> No such option -m. coverage run py.test test.py -> Unknown command py.test (py.test 已安装)
    • 抱歉,一个错字,现已修正。
    • @NedBatchelder 此方法在生成的报告中包含 test.py。在使用诸如覆盖率之类的工具时,这是否被认为是最佳实践?我的意思是要始终测量要测试的模块的覆盖率和测试本身吗?如果不是,我将如何从报告中排除 test.py 覆盖率?
    猜你喜欢
    • 2012-01-13
    • 1970-01-01
    • 2015-01-19
    • 2015-07-10
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    相关资源
    最近更新 更多