python module_error ai_generated true

AttributeError: <module 'myapp.services' from '/app/services.py'> 没有属性 'requests'

AttributeError: <module 'myapp.services' from '/app/services.py'> does not have the attribute 'requests'

ID: python/unittest-mock-patch-target-not-found

其他格式: JSON · Markdown 中文 · English
80%修复率
90%置信度
0证据数
2024-01-19首次发现

版本兼容性

版本状态引入弃用备注
3.8 active — — —
3.11 active — — —
3.12 active — — —

根因分析

unittest.mock.patch 针对的是名称被查找的位置,而非定义位置。若 services.py 使用 `import requests` 并调用 `requests.get`,应 patch 'myapp.services.requests.get';若使用 `from requests import get`,则应 patch 'myapp.services.get'。

English

unittest.mock.patch targets the name where it is looked up, not where it is defined. If services.py does `import requests` and calls `requests.get`, patch 'myapp.services.requests.get'. If it does `from requests import get`, patch 'myapp.services.get'.

generic

解决方案

  1. 95% 成功率
    Identify the binding style in the SUT and patch accordingly:
      # if SUT: import requests
      @patch('myapp.services.requests')
      def test_get(mock_req): ...
      # if SUT: from requests import get
      @patch('myapp.services.get')
      def test_get(mock_get): ...
  2. 90% 成功率
    Use pytest-mock's mocker fixture which resolves the same lookup semantics:
      def test_get(mocker):
          mocker.patch('myapp.services.requests.get')

无效尝试

常见但无效的做法:

  1. 75% 失败

    Patches the global requests module, not the reference the SUT uses; the real network call still fires.

  2. 80% 失败

    Creates a separate binding; the SUT's binding remains untouched.