简体   繁体   中英

pytest can't find module in Lambda function

I have a Lambda, created using the SAM CLI, with a single function. The function itself works just fine (both locally and when deployed) however pytest fails, suggesting that my function is unable to import a module within my directory structure.

Note that the directory structure is shown at the bottom of the question.

# 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

The only tests I have at present are to ensure that an error is returned when the HTTP method is not GET , DELETE or PUT . The line from core.exception import MethodNotAllowedException is indeed at line 2 of 'my-function/app.py', and as mentioned previously, the function is able to import this module without issue when running locally or when deployed to AWS.

Here is the error that pytest is encountering.

my-function/app.py:2: in <module>
    from core.exception import MethodNotAllowedException
E   ModuleNotFoundError: No module named 'core'

I have tried to move the modules to the same directory as 'app.py' but import still fails.

my-function/app.py:2: in <module>
    from exception import MethodNotAllowedException
E   ModuleNotFoundError: No module named 'exception'

I did also try to use relative imports, so I changed line 2 of 'my-function/app.py' to from.core.exception import MethodNotAllowedException . However, while pytest is now able to import the module, the function itself fails when using sam local invoke . So relative imports I believe are a non-starter.

Unable to import module 'app': attempted relative import with no known parent package

How can I get pytest to work with my function?

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.

File Structure

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

You can control what's added to sys.path using command line options like --import-mode . More information can be found at https://docs.pytest.org/en/6.2.x/pythonpath.html .

edit

If the import modes didn't work perhaps you can try adding the path yourself before the imports in your test, something like

import sys
sys.path.append('../../my-function')
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM