将 `runpy` 与 mocks 组合在单独 运行 时通过,但在 运行 其他测试时失败
Combining `runpy` with mocks passes when running alone but fails when running with other tests
当我运行单独进行以下测试时,它通过了。但是当我 运行 它与其他测试一起使用时,即使这个测试是第一个 运行 它失败了:
from runpy import run_path
from unittest.mock import patch, MagicMock
@patch('boto3.client', autospec=True)
def test_scripts(mock_boto3_client: MagicMock):
mock_boto3_client().head_object.return_value = {}
run_path(
'src/scripts/dynamic_script.py',
run_name='__main__'
)
这似乎会以某种方式受到其他模拟或导入的影响,但尚不清楚当 运行 首先
时它们将如何影响此测试
终于想通了。这是由于 mock.patch
的工作方式。这是一个很好的解释:
https://nedbatchelder.com/blog/201908/why_your_mock_doesnt_work.html
runpy
之所以难以理解,是因为当我们 运行 仅进行此测试时,即使补丁名称不正确,补丁也能正常工作。这可能是因为补丁是在导入 之前 完成的(导入在 run_path
期间动态发生),所以在 from/import
发生时,补丁已经存在在内存中,我们得到了指向模拟的指针。
当我们 运行 在其他测试的上下文中进行测试时,导入树包含使用 from boto3 import client
定义的原始库,因此此导入可能在应用补丁之前在内存中。
解决方案是确保所有对模拟实体的引用都是全名的,只使用 import boto3
,或者在测试模块中模拟名称。
当我运行单独进行以下测试时,它通过了。但是当我 运行 它与其他测试一起使用时,即使这个测试是第一个 运行 它失败了:
from runpy import run_path
from unittest.mock import patch, MagicMock
@patch('boto3.client', autospec=True)
def test_scripts(mock_boto3_client: MagicMock):
mock_boto3_client().head_object.return_value = {}
run_path(
'src/scripts/dynamic_script.py',
run_name='__main__'
)
这似乎会以某种方式受到其他模拟或导入的影响,但尚不清楚当 运行 首先
时它们将如何影响此测试终于想通了。这是由于 mock.patch
的工作方式。这是一个很好的解释:
https://nedbatchelder.com/blog/201908/why_your_mock_doesnt_work.html
runpy
之所以难以理解,是因为当我们 运行 仅进行此测试时,即使补丁名称不正确,补丁也能正常工作。这可能是因为补丁是在导入 之前 完成的(导入在 run_path
期间动态发生),所以在 from/import
发生时,补丁已经存在在内存中,我们得到了指向模拟的指针。
当我们 运行 在其他测试的上下文中进行测试时,导入树包含使用 from boto3 import client
定义的原始库,因此此导入可能在应用补丁之前在内存中。
解决方案是确保所有对模拟实体的引用都是全名的,只使用 import boto3
,或者在测试模块中模拟名称。