#python #amazon-web-services #python-unittest #python-unittest.mock
Вопрос:
Это функция AWS lambda
#service.py
from configs import SENDER, DESTINATIONS
from constants import LOG_FORMAT
import logging
def send_mail(body, SENDER, DESTINATIONS):
...
...
В файлах конфигурации он извлекает данные из хранилища параметров AWS
# configs.py
from handlers.ssm_handler import load_parameters
from common import constants
import os
environment = os.environ.get(constants.ENVIRONMENT)
JSON_BUCKET = load_parameters(constants.OT_ARCHIVAL_PREFIX environment constants.MIGRATION_BUCKET)
SENDER = load_parameters(constants.OT_ARCHIVAL_PREFIX environment constants.MAIL_SENDER)
DESTINATIONS = load_parameters(constants.OT_ARCHIVAL_PREFIX environment constants.MAIL_DESTINATIONS)
...
Поэтому, когда я пытаюсь это проверить
# test_service.py
from unittest import TestCase, main, mock
from service import send_mail
class TestMailService(TestCase):
def test_service(self):
with mock.patch('service.SENDER', 'abc@sys.com') as mocked_sender:
with mock.patch('service.DESTINATIONS', 'def@sys.com') as mocked_sender:
with mock.patch('service.logging.Logger.info') as mocked_logging:
send_mail(...)
mocked_logging.assert_called_with('mail sent Successfully')
Этот тестовый случай проходит, когда я экспортирую учетные данные безопасности AWS. Но это произойдет, если я не сдам документы. Я думаю, это потому, что в service.py файл он открывает весь config.py файл. Поэтому для вызова AWS потребуются учетные данные sec.
В качестве решения я попытался высмеять ОТПРАВИТЕЛЯ и АДРЕСАТОВ. Но это выдает мне ошибку(ожидание токенов безопасности)
Я хочу, чтобы unittest был независимым от токена безопасности. Предложите решение
Ответ №1:
Это происходит потому, что при импорте configs.py например , через from configs import SENDER, DESTINATION
, он автоматически запускал бы те операторы, которые вызывают load_parameters
, которые, в свою очередь, вызывают AWS SSM, даже если еще нет активных насмешек/исправлений.
Решение 1
Попробуйте провести рефакторинг configs.py таким образом, установка переменных будет происходить только при явном вызове (а не при импорте). Простейшей реализацией было бы что-то вроде:
configs.py
import os
from common import constants
from handlers.ssm_handler import load_parameters
def get_params():
environment = os.environ.get(constants.ENVIRONMENT)
return {
"SENDER": load_parameters(constants.OT_ARCHIVAL_PREFIX environment constants.MAIL_SENDER),
"DESTINATIONS": load_parameters(constants.OT_ARCHIVAL_PREFIX environment constants.MAIL_DESTINATIONS),
}
Для этого потребуется некоторый рефакторинг, так как вызов get_params
должен быть вставлен в начале вызова функции AWS Lambda. Таким образом, вызов load_parameters
, который, в свою очередь, использует AWS SSM, не будет выполняться автоматически, и мы сможем подготовить наши насмешки/исправления до его вызова.
Решение 2
Не импортируйте ни один файл, который, в свою очередь, импортировал бы configs.py пока еще нет активного макета/патча. load_parameters
Сначала исправьте, чтобы он не подключался к фактической SSM AWS. Вы можете исправить это вручную или использовать декоратор @mock_ssm
из moto. Только тогда мы сможем безопасно импортировать файлы.
from unittest import TestCase, main, mock
from moto import mock_ssm
# from service import send_mail # REMOVE THIS IMPORT!
@mock_ssm # Option 1. Requires <pip install moto>. You have to setup SSM first as usual.
def test_service(mocker): # Requires <pip install pytest-mock>
mocker.patch('handlers.ssm_handler.load_parameters') # Option 2
# with mock.patch('handlers.ssm_handler.load_parameters') as mock_ssm: # Option 3. This is equivalent to Option 2.
mocker.patch('service.SENDER', 'abc@sys.com')
mocker.patch('service.DESTINATIONS', 'def@sys.com')
from service import send_mail # Import it here after the patches have taken effect
send_mail(...)
Комментарии:
1. Для решения 2 разве нам не нужен класс?
2. Для решения 2 вы можете попробовать использовать классы вместе с вариантом 3. Я не пробовал, будет ли вариант 1 или 2 работать из коробки, вам может потребоваться дополнительная настройка.
3. Я попробовал вариант 3 с классом. это не работает
4. По-прежнему ли ошибка связана с отсутствием учетных данных AWS? Если это так, то
configs.py
все равно было выполнено до исправления. Проверьте, есть ли какие-либо предыдущие импортные операции, которые могут привести к импортуconfigs.py
. Кроме того, проверьте, является ли исправление, которое я сделал, правильным путем'handlers.ssm_handler.load_parameters'
, поскольку я основывал его только на вопросе.