Pytest 报告导入和常量赋值的覆盖范围中缺少行

问题描述 投票:0回答:1

我对项目中不同文件的覆盖行为差异感到困惑,希望有人建议如何比我现在更有效地调试它。这基本上与 Pytest 错误地报告覆盖范围中缺失的行

是同一个问题

我正在使用Python 3.11,tox 4.11.3,覆盖率7.4.4。如果有的话,可以在mbp笔记本电脑上工作。我的python代码文件都是这样的,我的包目录

myproj/
中的这个叫
coverme.py
:

import logging

logger = logging.getLogger(__name__)
some_obj = SomeObject(foo='bar')
CONST = 123


def myfunc() -> bool:
    return True


def otherfunc() -> bool:
    """
    nice pydoc goes here
    """
    return CONST

我的测试文件都是这样的,项目的

tests/
目录下的这个叫
test_coverme.py
:

import logging
from myproj import coverme

logger = logging.getLogger(__name__)


def test_myfunc():
    logger.debug('test myfunc')
    assert coverme.myfunc()

这是我的 tox.ini 文件:

[tox]
envlist = code,flake8
minversion = 2.0

[pytest]
testpaths = tests

[testenv:code]
basepython = python3
deps=
    coverage
    pytest
    pytest-cov
    pytest-mock

commands =
    pytest --cov myproj --cov-report term-missing --cov-fail-under=70 {posargs}

[testenv:flake8]
basepython = python3
skip_install = true
deps = flake8
commands = flake8 setup.py myproj tests

我可以通过

tox -- tests/test_coverme.py
运行测试并查看这些结果;我删除了无法在此处发布的文件的结果:

---------- coverage: platform darwin, python 3.11.7-final-0 ----------
Name                            Stmts   Miss  Cover   Missing
-------------------------------------------------------------
myproj/coverme.py                    7      1    86%   16

上面显示的简单

coverme
示例完美运行,pytest-cov 报告除第 16 行之外的所有行;我同意
otherfunc
永远不会被调用。我的项目中的大多数代码文件也是如此,报告的覆盖率符合我的预期。

然而,对于一些代码文件(我当然不能在这里发布),覆盖率报告列出了未覆盖(遗漏)的行,即导入语句和常量定义!例如,像

CONST = 123
这样的 pytest 声明行(出现在我上面发布的示例中)不会被任何测试覆盖。测试导入的文件中的常量赋值行似乎不可能不被执行。

我在报道常见问题解答中看到从命令行调用

coverage
的建议,我相信 tox 正在为我做这件事。我运行
coverage erase
来清理旧数据,这没有什么区别。我运行
tox -r
重新安装所有依赖项,也没有区别。我知道我可以使用 tox 运行单个测试文件或单个测试(不是完整套件),但我也没有发现这会产生影响。

请建议其他方法来找出我做错了什么,或者只是 pytest 做得不太正确,提前致谢。

python pytest tox coverage.py pytest-cov
1个回答
0
投票

缺乏类似的问题/答案让我非常确定我做错了什么,或者至少有点不寻常。我注意到第一行missed始终是此行之后的行:

api_client = ApiClient(client_config)

Pdb 中的大量跟踪确认这是有问题的代码行。 该类

ApiClient
是由
swagger-codegen
从 OpenAPI 规范 YAML 文件生成的。
ApiClient
类在其
__init__
方法中创建一个常规的Python3线程池,如下所示:

self.pool = ThreadPool()

Pool
类的
__init__
方法调用
_repopulate_pool
方法,该方法创建进程并在进程上调用
.start()
。此时,Python 调试器将停止跟踪并继续执行。我怀疑(但不知道如何证明)当
coverage
工具监视执行时会发生类似的情况,这就是它无法跟踪执行行的原因。

我的解决方案是一种解决方法。我没有使用模块顶部的 API 客户端初始化变量,而是添加了一个 getter 函数来延迟创建

ApiClient
的实例:

_api_client = None
def _get_api_client() -> ApiClient:
    """
    Initialize an API object lazily to simplify tox testing.
    :return: ApiClient
    """
    global _api_client
    if _api_client is None:
        client_config = Configuration()
        _api_client = ApiClient(client_config)
    return _api_client

对于毒性测试,我使用

mocker.patch
从这个 getter 函数返回一个假值,假的 bcos 我的测试套件不会模拟这些生成的客户端访问的远程 REST 服务。

完成所有这些后,我再次看到符合我预期的覆盖率结果,并且模块顶部的所有导入和赋值语句不再被错过。

也许这会对使用 Swagger 生成的代码的人有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.