考慮以下專案結構:
/project
- folder/
- some_config_module.py
- func.py
- test/
- __init__.py
- test_config.py
- test.py
假設以下代碼
# func.py
import folder.some_config_module as config
def search_for_data():
var = config.predefined_parameter
# rest of code
我現在想為search_for_data. 為了以一種明智的方式做到這一點,我需要模擬 的匯入some_config_module,即我的嘗試
# test.py
import unittest
from unittest.mock import patch
import tests.test_config as test_config
from folder.func import serach_for_data
class TestSearchForData(unittest.TestCase):
@patch('folder.some_config_module')
def test_one(self, test_config):
self.assertEqual(search_for_data(), 0)
if __name__ == "__main__":
unittest.main()
這不會導致預期的行為:我想要的是search_for_data內部test_one匯入test.test_config而不是folder.some_config_module. 這段代碼基于這個答案......但我似乎誤解了一些相當基本的mock......
uj5u.com熱心網友回復:
由于您的函式search_for_data使用的是config匯入到func的全域命名空間中的名稱,因此您需要覆寫它而不是覆寫folder.some_config_module.
@patch('folder.func.config')
類似的匯入import folder.some_config_module as config相當于執行以下操作:
import folder.some_config_module
config = folder.some_config_module
del folder.some_config_module
因此,它將變數添加config到那個 module( func.py) 的命名空間中,這就是當時search_for_data正在使用的。從search_for_data的角度來看,config是一個名稱是指一個模塊還是指其他東西并不重要,它只知道它需要從全域命名空間加載該名稱(在這種情況下它是模塊func.py)
在運行時search_for_data將config在其全域命名空間(search_for_data.__globals__)中查找,模擬修補此全域字典并用config模擬物件臨時替換此字典中的名稱,并在拆卸期間將其恢復。
import os.path as path
from unittest.mock import patch
def func():
print(path)
print(f"Before patch: {func.__globals__['path']}")
with patch("__main__.path"):
print(f"During patch: {func.__globals__['path']}")
func()
print(f"After patch: {func.__globals__['path']}")
輸出:
Before patch: <module 'posixpath' from '/usr/lib/python3.8/posixpath.py'>
During patch: <MagicMock name='path' id='140233829017776'>
<MagicMock name='path' id='140233829017776'>
After patch: <module 'posixpath' from '/usr/lib/python3.8/posixpath.py'>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/359931.html
標籤:Python 蟒蛇-3.x 单元测试 python-unittest python-unittest.mock
