python - 如果未安装可选模块,则测试代码行为
问题描述
我有一个软件包,packageA
,它对packageB
. 如果packageB
已安装,则用户可以访问一些附加功能。但是,没有安装它并不会限制packageA
.
我想编写一个单元(或集成?)测试,packageA
如果没有安装,检查仍然可用packageB
......也就是说,它不会意外地抛出一个ImportError
forpackagB
我的测试是这样写的:
from unittest import mock
import pytest
def test_no_err_if_packageb_not_installed():
import sys
sys.modules['packageB'] = mock.MagicMock()
try:
from packageA import file_that_uses_packageb # noqa: F401
except NameError:
pytest.fail("packagB dependency found at root level")
这有效,如果它被孤立地调用。但是当它作为测试套件的一部分被调用时,这个测试总是会通过。这是因为sys.modules
之前的测试已经用导入模块填充了。我del
从一开始就尝试过包装sys.modules
,但这不起作用
编写此测试的正确方法是什么?
使用工作解决方案进行编辑
from unittest import mock
import pytest
def test_no_err_if_packageb_not_installed():
import sys
# clear cached modules
mods = list(sys.modules.keys())
for mod in mods:
if 'packageA' in mod or 'packageB' in mod:
del sys.modules[mod]
sys.modules['packageB'] = mock.MagicMock()
try:
from packageA import file_that_uses_packageb # noqa: F401
except NameError:
pytest.fail("packagB dependency found at root level")
del sys.modules['packageB']
解决方案
为此进行黑客攻击sys.modules
是要走的路。问题是您正在packageB
重置的导入 - 但实际上,要进行此测试,您还必须重置file_that_uses_packageb
.
在您的测试设置中尝试del sys.modules["packageB"], sys.modules["packageA.file_that_uses_packageB"]
,您应该已经准备就绪。
不要忘记在测试结束时再次重置它们,否则实际使用的其他测试packageB
将失败。
(被诱人标记为“重复”的答案没有触及相同的点 - 答案谈到 using imp.reload
,它重置并重新运行一个模块,好的 - 但不允许你用模拟替换模块代码,如果需要)
推荐阅读
- javascript - Javascript Diff算法不适用于HTML代码
- android - 我们可以在全局范围内添加@Suppress 标志吗?
- javascript - 使用 html2Canvas 和 jsPDF 保存为 PDF,用于 php 应用程序 1 次在 3 中工作
- python - configparser 不显示部分
- jquery - 已解决:如何在两种颜色之间切换
- c++ - MDIchild 中的 QWidget 问题 - QAbstractScrollArea
- vue.js - 如何在Vuejs中处理浏览器后退按钮单击事件
- sql - Postgres 不使用带有 LEFT JOIN 或 OR in where 的索引
- php - 从 debug_backtrace 动态提取参数
- haproxy - HAProxy 削减日志中的参数