如何在pytest中使用monkeypatch或mock删除库?

时间:2020-09-12 22:52:24

标签: python pytest monkeypatching pytest-mock

如果我的库中有一个... Time elapsed: 00:01:02 secs ... Time elapsed: 22:10:53 secs ... 附加项(例如contrib),我希望用户必须安装该附加项才能访问CLI API,但是我在安装过程中安装了contrib extra我在CI中的测试如何在测试过程中使用pytest's MonkeyPatch删除依赖项以确保检测正确?

例如,如果requests附加项将另外安装contrib,那么我希望用户必须这样做

requests

然后可以在命令行中使用看起来像这样的CLI API

$ python -m pip install mylib[contrib]

其中$ 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) # ... 测试中模拟或猴子跳出 out requests,以便确保用户可以与{{1 }},如果他们这样做

pytest

?在阅读了pytest标签上的其他一些问题之后,我仍然认为我不知道该怎么做,所以我在这里问。

1 个答案:

答案 0 :(得分:0)

我最终所做的工作奏效了,并且我确认是一种合理的方法thanks to Anthony Sottile,是通过将其设置为{{来嘲笑额外的依赖项(这里requests)不存在。 1}},然后重新加载需要使用None的模块。 我测试是否存在实际的抱怨,即不存在使用sys.modules来导入requests的问题。

这是我目前正在使用的测试(名称更改为与上述问题中的玩具示例问题相匹配)

requests

我应该注意到,{hoefling}实际上是在@Abhyudai's answer to "Test for import of optional dependencies in init.py with pytest: Python 3.5 /3.6 differs in behaviour"中提倡的(上面我已经解决了这个问题,但是在我发表之前就发布了)。

如果人们有兴趣在实际的图书馆中看到这些,请参见c.f.以下两个PR:

注意: 安东尼·索提(Anthony Sottile)警告过

caplog可能有点麻烦-我会小心一点(具有对旧模块的旧引用的内容将继续存在,有时会引入单例的新副本(doubleton或Tripletons?)) -我已将许多测试污染问题归结为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()

因此,如果我采用更安全的替代方法,我将修改此答案。