我有一个软件包packageA
,它对packageB
有一个可选的依赖项。如果安装了 packageB
,则用户可以访问一些附加功能。但是,不安装它并不限制 packageA
的使用。
我想编写一个单元(或集成?)测试来检查 packageA
如果未安装 packageB
是否仍然可用...也就是说,它不会意外地为 packagB
ImportError
我的测试是这样写的:
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
已经由之前的测试填充了导入模块。我尝试先从 sys.modules
中del
包,但这不起作用
编写此测试的正确方法是什么?
使用工作解决方案进行编辑
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
的其他测试将失败。
(被试探性地标记为“重复”答案的答案并没有触及相同的点 - 答案谈到使用 imp.reload
,它重置并重新运行模块,好的 - 但是如果需要,将不允许您用模拟替换模块代码)
关于python - 如果未安装可选模块,则测试代码的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60746184/