Часть 7 - Тестирование

Пока что мы экспериментировали в создании приложений для воображаемого мира, где все работает с первой попытки, никогда не меняется и ничего не ломается. Что ж, извините, что разочаровал вас, но реальный мир выглядит немного иначе, и есть важный аспект, который мы еще не затронули, тестирование.

Любимое или ненавистное, рассматриваемое как трата времени или спаситель, вы всегда должны добавлять некоторый уровень тестирования для своего приложения. Единица, интеграция, сквозное соединение, инфраструктура, производительность, проникновение - есть множество возможностей для тестирования приложения, и, надеюсь, в конце концов вы их все охватите.

Мы не будем сосредотачиваться на теории тестирования, но рассмотрим несколько примеров того, как выполнять модульные / интеграционные тесты для бессерверных приложений, написанных с помощью инфраструктуры SAM.

В этой первой части мы не будем использовать вспомогательные функции SAM, а будем использовать старую добрую vanilla pytest. Как обычно, вы можете найти исходный код на моей странице GitHub.

Предположим, у нас есть простое приложение, которое предоставляет два API, поддерживаемых двумя Lambda, один из которых используется для создания записи в таблице DynamoDB, а другой - для получения созданной записи, а также уровень для создания ответа, соответствующего требованиям шлюза API (даже если HTTP API может справиться с этим).

Код для первого API может выглядеть примерно так

а код для второго API может выглядеть так

Код очень простой, потому что я хочу сосредоточиться на тестировании. Но для производственного кода всегда используйте передовые методы кодирования - обрабатывайте ошибки, используйте регистратор, проверяйте ввод и т. Д. Итак, давайте перейдем к некоторым тестовым примерам.

Первый тест, который мы можем выполнить, - это удачный путь для вставки данных в DynamoDB. Благодаря простоте приложения это можно преобразовать в прямой вызов функции lambda_handler, а благодаря простоте развертывания таблицы DynamoDB мы можем напрямую взаимодействовать с таблицей, развернутой на AWS, избегая имитации или локальной копии сервиса, очевидно , таблица должна быть создана с помощью SAM. Обратите внимание на то, что роль, которую вы используете для взаимодействия с AWS, имеет достаточно разрешений для чтения и записи в DynamoDB и правильно установлена ​​локально.

Этот тест считывает json файл, содержащий образец события API Gateway, вызывает lambda_handler с этим событием, проверяет правильный код состояния ответа и, наконец, проверяет, действительно ли данные были созданы в таблице AWS DynamoDB, как ожидалось. Следует обратить внимание на одну важную вещь: параметр lambda_context, переданный в тест, прибор, функция, выполняемая перед тестом, которая принимает в качестве параметра возвращаемое значение прибора, поэтому в нашем случае мы используем его для имитируйте объект контекста лямбда. Приспособления очень удобны, и мы могли бы использовать эту конструкцию также для параметризации построения лямбда-событий.

Еще одна вещь, на которую следует обратить внимание, - это как сообщить Python, где находятся все модули. После развертывания наша Lambda знает, где находятся код, зависимости и уровень, но локально нам нужно выполнить некоторую настройку. Python использует концепцию PythonPATH для поиска модулей - списка системных путей, по которым интерпретатор Python будет искать модули. Существует множество способов структурировать код и отредактировать этот список. Например, если вы используете PyCharm в качестве предпочтительной среды IDE, вы можете пометить каталог как исходный корень непосредственно из среды IDE, щелкнув правой кнопкой мыши нужную папку и выбрав Mark Directory as --> Sources Root. Для нашей структуры важно пометить папки tests и layer как исходный корень, первая для правильного разрешения кода лямбда из тестового примера, а вторая для разрешения общего кода в слое. Другой альтернативой разрешению лямбда-кода из тестового примера мог быть относительный импорт с нотацией ... Наконец, если вам нужна большая гибкость, вы можете редактировать напрямую PythonPATH env var или из кода с помощью метода sys.path.append(). Но есть еще много способов сделать это.

Второй тест, который мы можем выполнить, - это удачный путь для получения данных. Мы можем действовать тремя способами: имитировать ответ DynamoDB, настроить запись в DynamoDB или запустить локальную копию DynamoDB. Из-за простоты развертывания DynamoDB мы можем использовать подход, аналогичный предыдущему, вызывая напрямую lambda_handler функцию, предварительно заполняя таблицу, вызывая непосредственно DynamoDB SDK или вызывая нашу функцию, которая гарантированно будет работать в предыдущем тесте. Здесь снова на руку конструкция фикстуры pytest.

Таким образом, мы можем вставить тестовую запись в таблицу DynamoDB, выполнить тест и после этого очистить таблицу. Метод yeld будет ожидать завершения выполнения теста, обрабатывая автоматическую очистку только после выполнения теста, в то время как свойство scope=module фикстуры принудительно запускает его выполнение при запуске модуля.

Другой подход заключается в использовании возможностей встроенной заглушки boto3. Идея состоит в том, чтобы заменить клиент таблицы заглушкой, в нашем случае переменной table. Теперь мы можем использовать стаббер, чтобы заставить ложный ответ для get_item метода. Встроенный стаббер boto3 также подтверждает, что структура, которую мы используем, соответствует реальной. Теперь нам нужно только активировать стаббер и вызвать обычный lambda_handler, который, как только он достигнет метода get_item, вместо попадания в таблицу DynamoDB будет возвращать ложный ответ заглушки. При таком подходе мы проводим настоящий модульный тест без тестирования сторонних сервисов.

Мы только прикоснулись к миру тестирования, и в следующих главах мы увидим, как повысить уровень автоматизации наряду с другими способами тестирования нашего приложения.

Больше контента на plainenglish.io