python - 如何正确修补模块级属性?
问题描述
我有一个用 Python 编写的 Lambda 函数,如下所示:
# lambda_function.py
from data_manager import DataManager
_data_manager = DataManager()
def lambda_handler(event, context):
return _data_manager.do_something(event['value'])
DataManager 实例存储在模块级属性中,因为创建它有点昂贵。这样,它只在冷启动时创建。它看起来像这样:
# data_manager.py
from os import environ
class DataManager:
def __init__(self):
self._api_key = environ['ApiKey']
def do_something(self, value: int):
return value * 2
实际上它更复杂,但这说明了我遇到的问题,即我无法弄清楚如何在单元测试中正确修补 DataManager。这是我尝试的第一件事:
# test_lambda_function.py
from unittest.mock import patch
@patch('lambda_function._data_manager', autospec=True)
def test_lambda_handler(mock_data_manager):
print('test_lambda_handler called')
此测试失败,因为environ['ApiKey']
未设置。我的期望是该DataManager.__init__
方法不会被调用,因为lambda_function._data_manager
已修补,但显然这不起作用。我认为该'test_lambda_handler called'
消息甚至从未打印过,因为在解释器处理@patch
注释时会发生错误。接下来,我尝试了这个:
# test_lambda_function.py
from unittest.mock import patch
@patch('lambda_function.DataManager', autospec=True)
def test_lambda_handler(mock_data_manager):
print('test_lambda_handler called')
此测试失败的原因与前一个相同。下一次尝试:
# test_lambda_function.py
from unittest.mock import patch
@patch('data_manager.DataManager', autospec=True)
def test_lambda_handler(mock_data_manager):
print('test_lambda_handler called')
这个测试通过了,但是当它变得更复杂时我遇到了更多问题,我使用相同的方法添加了另一个测试:
# test_lambda_function.py
from unittest.mock import patch
@patch('data_manager.DataManager', autospec=True)
def test_lambda_handler(mock_data_manager):
print('test_lambda_handler called')
event = {'value': 1}
expected = 2
mock_data_manager.return_value.do_something.return_value = expected
from lambda_function import lambda_handler
actual = lambda_handler(event, {})
assert expected == actual
@patch('data_manager.DataManager', autospec=True)
def test_lambda_handler_again(mock_data_manager):
print('test_lambda_handler_again called')
event = {'value': 2}
expected = 4
mock_data_manager.return_value.do_something.return_value = expected
from lambda_function import lambda_handler
actual = lambda_handler(event, {})
assert expected == actual
在这种情况下,第一个测试通过,但第二个测试失败,因为lambda_function._data_manager
仍然引用第一个测试中使用的前一个模拟实例。显然,该属性仅在导入模块时分配lambda_function
,并且每个测试模块仅导入一次,而不管每个测试lambda_handler
单独导入该功能。
我唯一的另一个想法是根本不测试lambda_function
模块,但由于各种原因,这并不是一个真正的选择。
解决方案
推荐阅读
- angular - RxJs:如何跨多个组件维护一个 WebSocket 连接?
- mysql - 我更改了我的 MAMP httpd.conf,现在 Apache 服务器无法启动
- r - 我应该如何用该列的平均值估算 NA,而不仅仅是替换 na 值?
- javascript - docker的nodejs env设置
- python - 嵌套 python 字典不是添加新值,而是更新它
- android - 无法将方法调用“记住”内联到 @androidx.compose.runtime.Composable
- ios - React Native 运行 ios 仅在终端上失败
- reactjs - 反应 2 条类似的路线重叠并仅导致 1 条显示
- python - 使用名称调用另一个文件中的函数
- javascript - 如何使用下拉列表计算jQuery中的总数