pytest-mock模拟导入包内函数失败,请求排查问题原因
问题原因及解决方案
核心问题
模拟失效的本质是Python导入机制导致的引用不匹配:
当你用from mypackage.mymodule import get_a时,get_a已经被复制到测试文件的命名空间中。此时你补丁的是mypackage.mymodule里的原函数,但测试代码调用的是测试文件里已导入的get_a引用,两者不是同一个对象,所以模拟不会生效。
两种可行解决方案
方案1:补丁测试模块自身的get_a引用
直接修改fixture,补丁当前测试文件里的get_a,逻辑和本地定义时一致:
import pytest from mypackage.mymodule import A, get_a @pytest.fixture def mocked_A(mocker): a = A(2) # 补丁当前测试模块中的get_a引用 mocker.patch(f"{__name__}.get_a", return_value=a) def test_mocked_a(mocked_A) -> None: a = get_a() assert a.value == 2
方案2:通过原模块访问get_a
修改测试代码,不直接导入get_a,而是导入整个模块,通过模块调用函数,这样补丁原模块的get_a会直接生效:
import pytest from mypackage import mymodule from mypackage.mymodule import A @pytest.fixture def mocked_A(mocker): a = A(2) mocker.patch("mypackage.mymodule.get_a", return_value=a) def test_mocked_a(mocked_A) -> None: # 通过原模块调用get_a a = mymodule.get_a() assert a.value == 2
补充说明
本地定义时测试生效,是因为get_a本身就在测试模块里,补丁和调用的是同一个对象;移到外部包后,导入行为导致了引用分离,才出现模拟失效的问题。
内容的提问来源于stack exchange,提问作者Vince
相关产品推荐
相关产品推荐

