繁体   English   中英

从 pip 移动到诗歌,现在 pytest-cov 不会收集覆盖率数据

[英]Moved from pip to poetry and now pytest-cov won't collect coverage data

我最近开始使用poetry来管理项目依赖项,而不是使用requirements.txttest-requirements.txtpip

由于进行了更改,我无法让覆盖测试正常工作。 在这两种情况下,我都使用tox来驱动测试(并且我安装了tox-poetry扩展)。

我的tox.ini目前看起来像这样:

[tox]
isolated_build = True
envlist = pep8,unit

[testenv]
whitelist_externals = poetry

[testenv:venv]
commands = {posargs}

[testenv:pep8]
commands =
    poetry run flake8 {posargs:symtool}

[testenv:unit]
commands =
    poetry run pytest --cov=symtool {posargs} tests/unit

以前,它看起来像这样:

[tox]
envlist = pep8,unit

[testenv]
usedevelop = True
install_command = pip install -U {opts} {packages}
deps = -r{toxinidir}/requirements.txt
    -r{toxinidir}/test-requirements.txt

[testenv:venv]
commands = {posargs}

[testenv:pep8]
commands =
    flake8 {posargs:symtool}

[testenv:unit]
commands =
    pytest --cov=symtool {posargs} tests/unit

自从对poetry进行更改后,当我运行例如tox -e unit时,我看到:

unit run-test: commands[0] | poetry run pytest --cov=symtool tests/unit
===================================== test session starts =====================================
platform linux -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
cachedir: .tox/unit/.pytest_cache
rootdir: /home/lars/projects/symtool, configfile: tox.ini
plugins: cov-2.11.1
collected 14 items

tests/unit/test_disasm.py .....                                                         [ 35%]
tests/unit/test_symtool.py .........                                                    [100%]r
Coverage.py warning: No data was collected. (no-data-collected)

我试图找出no-data-collected问题。 根据pytest --help--cov arguments 设置路径package 名称:

 --cov=[SOURCE]        Path or package name to measure during execution

存储库的根目录(即上面来自tox的 output 中的rootdir )如下所示:

asm
pyproject.toml
README.md
reference
symtool
tests
tox.ini

那里肯定有一个symtool目录,其中包含 package。 即使测试没有在项目根目录中运行, symtool package 也会安装在测试环境中,单元测试实际上是通过的事实证明了这一点(所有这些都包括import symtool的一些变体)。

我怎样才能让保险再次发挥作用?

将我的评论变成答案:

这是pytest-covtox的一个老问题(在issue #38中首次报告)。 tox将您的项目安装为第三方 package 和pytest将从站点导入它(例如,如果作业名为unit ,则从.tox/unit/lib/python3.X/site-packages导入),而--cov=symtool指示pytest-cov收集项目根目录中symtool目录的覆盖率。

一种解决方案是切换到src布局:

├── pyproject.toml
├── README.md
├── reference
├── src
|   └── symtool
├── tests
└── tox.ini

在您的pyproject.toml中,您需要将poetry指向源目录:

[tool.poetry]
...
packages = [
    { include = "symtool", from = "src" },
]

现在src将阻止从源代码树导入代码,因此--cov=symtool将收集已安装模块的覆盖率,这是唯一的选择。 对于开发过程的 rest,您不应该遇到麻烦,因为poetry install会以可编辑模式安装项目,因此 rest 应该可以正常工作。

另一种选择是使用tox跳过 package 安装并以可编辑模式安装。 放置在tox.ini中的示例代码段:

[testenv]
whitelist_externals =
    poetry
skip_install = true
commands_pre =
    poetry install
commands =
    poetry run pytest ...

不过,这几乎会扼杀对已安装模块的测试(您停止明确测试您的项目是否可以安装在空白 venv 中,而不是使用源代码树中的内容),所以我将 go 与src布局选项。

如果您使用的是诗歌,您可能也喜欢在 tox 中使用 pytest、flake8、... 的锁定依赖项。 这可以通过tox-poetry-installer来实现。

为确保您的测试针对构建和安装的 package 而不是本地文件运行,您必须对 pytest 使用--import-mode标志并将其设置为importlib

要使用 pytest-cov 测量覆盖率,您必须指向{envsitepackagesdir}

总而言之,您的tox.ini可能如下所示:

[tox]
isolated_build = true
requires =
    tox-poetry-installer[poetry] == 0.6.0
envlist = py39

[testenv]
locked_deps =
    pytest
    pytest-cov
commands = pytest --cov {envsitepackagesdir}/mypackage --import-mode=importlib

--import-mode在做什么?

要运行测试, pytest需要导入测试模块。 传统上,这是通过将发现的测试文件夹所在的根文件夹的路径添加到sys.path来完成的。 通常测试文件夹和 package 文件夹共享同一个根文件夹。 所以添加到 sys.path 的副作用是,测试针对 package 文件夹而不是安装的 package 运行,因为 python 首先找到这个文件夹。

而不是预先添加到sys.path ,可以建议pytest到 append 发现的根文件夹。 执行此操作 python 将在尝试导入时首先查看 site-packages 文件夹。 因此,可以针对已安装的 package 进行测试。

操纵sys.path几乎总是一个坏主意,因为它会导致不必要的副作用。 pytest文档描述了一个:

和 prepend 一样,当测试目录树没有在包中排列时,要求测试模块名称是唯一的,因为模块在导入后会放在 sys.modules 中。

importlib 的第三个选项是在importlib 6 中引入的。它使用importlib来动态加载测试模块,而无需操作sys.path 他们计划在未来的版本中将此选项设为默认选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM