pytest 在 Lambda 函数中找不到模块
pytest can't find module in Lambda function
我有一个 Lambda,它是使用 SAM CLI 创建的,只有一个函数。该函数本身工作正常(在本地和部署时)但是 pytest
失败,表明我的函数无法在我的目录结构中导入模块。
注意目录结构显示在问题的底部。
# All commands are run from the 'Lambda' directory.
# With the 'sam' commands, the expected message is returned both locally and when deployed.
sam build -u
sam local invoke MyFunction --event events/405-get.json
sam deploy
# But the 'pytest' command fails.
python -m pytest tests/unit -v
我目前唯一的测试是确保HTTP方法不是GET
、DELETE
或PUT
时返回错误。 from core.exception import MethodNotAllowedException
行确实在 'my-function/app.py' 的第 2 行,并且如前所述,当 运行 在本地或部署到 AWS 时,该函数能够毫无问题地导入此模块。
这是 pytest
遇到的错误。
my-function/app.py:2: in <module>
from core.exception import MethodNotAllowedException
E ModuleNotFoundError: No module named 'core'
我已尝试将模块移动到与 'app.py' 相同的目录,但导入仍然失败。
my-function/app.py:2: in <module>
from exception import MethodNotAllowedException
E ModuleNotFoundError: No module named 'exception'
我也尝试过使用相对导入,所以我将 'my-function/app.py' 的第 2 行更改为 from .core.exception import MethodNotAllowedException
。然而,虽然 pytest
现在可以导入模块,但在使用 sam local invoke
时函数本身会失败。所以我认为相对进口是行不通的。
Unable to import module 'app': attempted relative import with no known parent package
如何让 pytest
使用我的函数?
test_handler.py
from proxy import app
import json
import os
import pytest
@pytest.fixture(scope='function')
def mock_context(mocker):
mock_context = mocker.MagicMock()
mock_context.aws_request_id = '00000000-0000-1000-0000-000000000000'
return mock_context
@pytest.fixture(scope='function')
def event(request):
dir = '{0}/../../events'.format(os.path.dirname(os.path.abspath(__file__)))
name = request.param
path = '{0}/{1}'.format(dir, name)
with open(path) as f:
event = f.read()
return event
class TestMethodNotAllowed:
@pytest.mark.parametrize(
'event', ['405-get.json'], indirect=True)
def test_405_get(self, event, mock_context):
'''Test a GET event.'''
response = app.lambda_handler(json.loads(event), mock_context)
body = json.loads(response['body'])
assert response['statusCode'] == 405
assert 'exception' in body
assert 'error_message' in body['exception']
assert body['exception']['error_message'] == 'Method not allowed.'
assert body['exception']['error_type'] == 'MethodNotAllowedException'
assert body['exception']['http_method'] == 'GET'
# Tests for PUT and DELETE also exist.
文件结构
Lambda
├── __init__.py
├── samconfig.toml
├── template.yaml
├── events
| ├── 405-delete.json
| ├── 405-get.json
| └── 405-put.json
├── my-function
| ├── init.py
| ├── app.py
| ├── requirements.txt
| └── core
| ├── __init__.py
| ├── exception.py
| ├── someotherfile.py
| └── morefiles.py
└── test
├── __init__.py
├── requirements.txt
└── unit
├── __init__.py
└── test_handler.py
您可以使用 --import-mode
等命令行选项控制添加到 sys.path
的内容。可以在 https://docs.pytest.org/en/6.2.x/pythonpath.html.
找到更多信息
编辑
如果导入模式不起作用,也许您可以尝试在测试中导入之前自己添加路径,例如
import sys
sys.path.append('../../my-function')
...
我有一个 Lambda,它是使用 SAM CLI 创建的,只有一个函数。该函数本身工作正常(在本地和部署时)但是 pytest
失败,表明我的函数无法在我的目录结构中导入模块。
注意目录结构显示在问题的底部。
# All commands are run from the 'Lambda' directory.
# With the 'sam' commands, the expected message is returned both locally and when deployed.
sam build -u
sam local invoke MyFunction --event events/405-get.json
sam deploy
# But the 'pytest' command fails.
python -m pytest tests/unit -v
我目前唯一的测试是确保HTTP方法不是GET
、DELETE
或PUT
时返回错误。 from core.exception import MethodNotAllowedException
行确实在 'my-function/app.py' 的第 2 行,并且如前所述,当 运行 在本地或部署到 AWS 时,该函数能够毫无问题地导入此模块。
这是 pytest
遇到的错误。
my-function/app.py:2: in <module>
from core.exception import MethodNotAllowedException
E ModuleNotFoundError: No module named 'core'
我已尝试将模块移动到与 'app.py' 相同的目录,但导入仍然失败。
my-function/app.py:2: in <module>
from exception import MethodNotAllowedException
E ModuleNotFoundError: No module named 'exception'
我也尝试过使用相对导入,所以我将 'my-function/app.py' 的第 2 行更改为 from .core.exception import MethodNotAllowedException
。然而,虽然 pytest
现在可以导入模块,但在使用 sam local invoke
时函数本身会失败。所以我认为相对进口是行不通的。
Unable to import module 'app': attempted relative import with no known parent package
如何让 pytest
使用我的函数?
test_handler.py
from proxy import app
import json
import os
import pytest
@pytest.fixture(scope='function')
def mock_context(mocker):
mock_context = mocker.MagicMock()
mock_context.aws_request_id = '00000000-0000-1000-0000-000000000000'
return mock_context
@pytest.fixture(scope='function')
def event(request):
dir = '{0}/../../events'.format(os.path.dirname(os.path.abspath(__file__)))
name = request.param
path = '{0}/{1}'.format(dir, name)
with open(path) as f:
event = f.read()
return event
class TestMethodNotAllowed:
@pytest.mark.parametrize(
'event', ['405-get.json'], indirect=True)
def test_405_get(self, event, mock_context):
'''Test a GET event.'''
response = app.lambda_handler(json.loads(event), mock_context)
body = json.loads(response['body'])
assert response['statusCode'] == 405
assert 'exception' in body
assert 'error_message' in body['exception']
assert body['exception']['error_message'] == 'Method not allowed.'
assert body['exception']['error_type'] == 'MethodNotAllowedException'
assert body['exception']['http_method'] == 'GET'
# Tests for PUT and DELETE also exist.
文件结构
Lambda
├── __init__.py
├── samconfig.toml
├── template.yaml
├── events
| ├── 405-delete.json
| ├── 405-get.json
| └── 405-put.json
├── my-function
| ├── init.py
| ├── app.py
| ├── requirements.txt
| └── core
| ├── __init__.py
| ├── exception.py
| ├── someotherfile.py
| └── morefiles.py
└── test
├── __init__.py
├── requirements.txt
└── unit
├── __init__.py
└── test_handler.py
您可以使用 --import-mode
等命令行选项控制添加到 sys.path
的内容。可以在 https://docs.pytest.org/en/6.2.x/pythonpath.html.
编辑
如果导入模式不起作用,也许您可以尝试在测试中导入之前自己添加路径,例如
import sys
sys.path.append('../../my-function')
...