如果我的图书馆有一个contrib
带有依赖于它(比如额外的requests
),我希望用户必须安装有访问CLI API,但我在我的CI测试中如何使用安装的contrib额外pytest
的MonkeyPatch
去除测试过程中的依赖性以确保我的检测正确吗?
例如,如果contrib
额外安装了额外的设备requests
,那么我希望用户必须这样做
$ python -m pip install mylib[contrib]
然后可以在命令行中使用看起来像这样的CLI API
$ mylib contrib myfunction
在哪里myfunction
使用requests
依赖
# mylib/src/mylib/cli/contrib.py
import click
try:
import requests
except ModuleNotFoundError:
pass # should probably warn though, but this is just an example
# ...
@click.group(name="contrib")
def cli():
"""
Contrib experimental operations.
"""
@cli.command()
@click.argument("example", default="-")
def myfunction(example):
requests.get(example)
# ...
我怎么嘲笑或猴补丁出 requests
在我pytest
的测试,这样我可以确保用户将正确地与相处的警告ModuleNotFoundError
,如果他们只是做
$ python -m pip install mylib
$ mylib contrib myfunction
?在阅读了pytest标签上的其他问题之后,我仍然不知道我该怎么做,所以我在这里问。
我最终做了这项工作,并通过Anthony Sottile确认了一种合理的方法,是requests
通过将它设置为None
insys.modules
并重新加载将要加载的模块来嘲笑不存在额外的依赖项(在此处)。需要使用requests
。我测试requests
了使用不存在要导入的实际投诉caplog
。
这是我目前正在使用的测试(名称更改为与上面问题中的玩具示例问题匹配)
import mylib
import sys
import logging
import pytest
from unittest import mock
from importlib import reload
from importlib import import_module
# ...
def test_missing_contrib_extra(caplog):
with mock.patch.dict(sys.modules):
sys.modules["requests"] = None
if "mylib.contrib.utils" in sys.modules:
reload(sys.modules["mylib.contrib.utils"])
else:
import_module("mylib.cli")
with caplog.at_level(logging.ERROR):
# The 2nd and 3rd lines check for an error message that mylib throws
for line in [
"import of requests halted; None in sys.modules",
"Installation of the contrib extra is required to use mylib.contrib.utils.download",
"Please install with: python -m pip install mylib[contrib]",
]:
assert line in caplog.text
caplog.clear()
我应该注意到,这实际上是@Abhyudai对“使用pytest在init .py中测试导入可选依赖项:Python 3.5 /3.6的行为有所不同”的答案所倡导的,@ hoefling链接到上面(在我解决了此问题后发布,在我发布此信息之前)。
如果人们有兴趣在实际的库中看到此内容,请参考以下两个PR:
注意:Anthony Sottile警告说
reload()
可能有点不确定-我会小心一点(对旧模块有旧引用的东西会继续存在,有时它会引入单例(doubletons?Tripletons?)的新副本)-我追踪了很多-测试污染问题reload()
因此,如果实施更安全的替代方法,我将修改此答案。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句