python - 如何在pytest中删除带有monkeypatch或mock的库?
问题描述
如果我的库有一个contrib
额外的依赖项(比如requests
),我希望用户必须安装才能访问 CLI API,但是我在 CI 中的测试期间安装了额外的 contrib 如何使用pytest
'sMonkeyPatch
删除测试期间的依赖关系以确保我的检测是正确的?
例如,如果contrib
额外安装requests
,那么我希望用户必须这样做
$ python -m pip install mylib[contrib]
然后能够在命令行拥有一个看起来像的 CLI API
$ mylib contrib myfunction
wheremyfunction
使用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
不存在通过 using 导入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()
可能有点不确定——我会小心处理(对旧模块有旧引用的东西会继续存在,有时它会引入单例的新副本(双联?三联?))——我已经找到了很多-a-test-污染问题reload()
因此,如果我实施更安全的替代方案,我将修改此答案。
推荐阅读
- typescript - “控制台”类型上不存在属性“详细”
- python - 什么是管道 | 和 >> 在 python 中?
- java - 我收到 java.io.IOException: Broken pipe 当响应数据很大时
- python - 在 Python 中,作为 Iam 循环遍历文件目录,如何在根目录输入文本文件并将匹配 re 的字符串替换为 xxxxx
- ember.js - 当模型被侧载时,ember-cli-mirage 失去关系
- r - mutate_at 在具有不同功能的多组列上
- php - 仅从 array_column 数组返回中提取字符串
- git - 带注释的标签和轻量级标签有什么区别?
- sql - 如何区分两个日期 SQL 服务器
- powershell - PowerShell 从网站下载 Txt 文件