Бессерверные вычисления - это больше, чем модель выполнения облачных вычислений. Это меняет способ планирования, создания и развертывания приложений. Но это также меняет способ тестирования наших приложений.

Познакомьтесь с Алексом. Алекс - обычный разработчик JavaScript, в последнее время сосредоточился на Node.js.

Последние пару месяцев его хорошие друзья Анна и Джефф постоянно говорят об этой бессерверной штуке. Даже несмотря на то, что они время от времени раздражают, ему нравится идея бессерверных приложений. В какой-то момент он даже развернул несколько простых функций в AWS Lambda и Azure.

В какой-то момент у Алекса и его команды появился новый проект. После некоторого анализа Алекс подумал, что это идеально подходит для бессерверной версии. Он представил идею своей команде. Некоторые участники команды были в восторге, кому-то это не понравилось, но у большинства не было твердого мнения. Итак, они решили попробовать - проект был не слишком большим, а риск был низким.

Команда прочитала о бессерверных приложениях и поняла, как структурировать свое новое приложение. Но никто не знал, как они должны вписаться в бессерверный процесс разработки.

На данный момент их процесс выглядит так:

  1. Они анализируют новую функцию.
  2. Для менее сложных функций они начинают с кода, затем запускают его локально и в конце добавляют несколько тестов.
  3. Для более сложных функций они используют свою версию TDD: они начинают с тестов, затем пишут код и тестируют его локально.
  4. Когда функция готова, она переходит к инструменту CI, который развертывает ее в среде тестирования.
  5. Затем команда QA берет новую функцию для еще одного раунда ручного тестирования. Если все в порядке, приложение переходит через CI в рабочую среду.

Они решили начать постепенно, а затем решать проблемы по мере их возникновения.

Они выбрали небольшую функцию и, поскольку она была простой, начали с кода. Когда часть кодирования была готова, они столкнулись с первым препятствием: как локально запускать бессерверные приложения?

Локальное тестирование

С бессерверными приложениями вы не управляете инфраструктурой. Звучит здорово, но как потом запустить приложение локально? Ты вообще можешь это сделать?

В зависимости от вашего приложения и бессерверного поставщика вы можете запускать некоторые части вашего приложения локально. Для этого вы можете использовать следующие инструменты и методы:

Конечно, это не полный список - инструментов стало больше, и мы видим новые инструменты сейчас почти каждый день.

У большинства этих инструментов есть определенные ограничения. Они могут имитировать бессерверные функции и некоторые другие службы, такие как API Gateway. Но как насчет разрешений, уровня аутентификации и других служб?

Локальное тестирование помогает быстро проверить, работает ли ваша функция. Но есть ли лучший способ убедиться, что ваше бессерверное приложение работает должным образом? Да, есть. Первый и самый важный шаг: напишите тесты.

Итак, Алекс и его команда опробовали свою первую функцию локально, и, похоже, она работала. Затем они перешли к следующему шагу.

Автоматизированные тесты

Алекс и его команда только что перешли на Jest для тестирования своих приложений Node.js. Они по-прежнему много работают с клиентской частью, поэтому они хотят использовать одни и те же инструменты для полного стека, когда это возможно. Могут ли они использовать Jest для тестирования бессерверных приложений? А что им тестировать?

После быстрого расследования они поняли, что могут использовать свои любимые инструменты тестирования Node.js. Jest, Jasmine, Mocha и другие отлично работают с serverless.

Что нужно тестировать в бессерверном приложении?

Создавая свои приложения Node.js, Алекс и его команда следуют трехуровневой пирамиде автоматизации тестирования. О тестовой пирамиде впервые упомянул Майк Кон в своей книге Успех с помощью Agile.

Как определяет тестовая пирамида, у них есть:

  • Множество модульных тестов, потому что они самые дешевые (самые быстрые в написании и запуске)
  • Меньше интеграционных тестов, потому что они дороже и требуют больше времени для выполнения
  • Несколько тестов пользовательского интерфейса, потому что они самые дорогие (требуется некоторый графический интерфейс) и самые медленные для выполнения.

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

Как бессерверность влияет на пирамиду автоматизации тестирования?

Ответ зависит от уровня. Но тестовая пирамида больше похожа не на египетские пирамиды, а на пирамиды майя.

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

Уровень интеграционных тестов становится более важным, чем когда-либо, потому что бессерверные приложения в значительной степени зависят от интеграции. Это также дешевле, потому что наличие бессерверной базы данных только для тестирования обходится дешево. Итак, в бессерверной «тестовой пирамиде» вам нужно больше интеграционных тестов.

Уровень тестирования графического интерфейса пользователя также дешевле и быстрее из-за более дешевого распараллеливания.

Уровень ручного тестирования остается прежним. Но бессерверный режим может помочь вам немного улучшить его. Мы поговорим об этом позже.

Алекс и его команда наконец-то поняли, на чем сосредоточиться. Следующая проблема заключалась в том, как написать функцию, чтобы упростить их тестирование.

Как написать тестируемые бессерверные функции

При написании бессерверной функции вам необходимо подумать о следующих рисках:

  • Риски конфигурации. Правильны ли база данных и таблица? Или у вас есть права доступа?
  • Технические риски рабочего процесса Анализируете и используете ли вы входящий запрос должным образом? Или вы правильно обрабатываете успешные ответы и ошибки?
  • Риски бизнес-логики Соблюдали ли вы все правила бизнес-логики, которые есть в вашем приложении?
  • Риски интеграции. Правильно ли вы читаете структуру входящего запроса? Или вы правильно храните заказ в базе?

Чтобы убедиться, что ваша бессерверная функция работает правильно, вам необходимо протестировать все эти риски.

Вы можете протестировать каждый из них, как вы это делали для интеграционных тестов. Но установка и настройка службы каждый раз, когда вы хотите протестировать один из этих рисков, не оптимальны. Как любит говорить мой друг Александр Симович:

Представьте, если бы так проводились испытания автомобилей. Это означало бы, что каждый раз, когда вы хотели проверить один-единственный винт или даже зеркало в машине, вам нужно было собрать, а затем разобрать всю машину.

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

Один из прекрасных способов сделать это - применить гексагональную архитектуру к вашим бессерверным функциям.

Гексагональная архитектура или Порты и адаптеры - это форма архитектуры приложения, которая способствует разделению задач по уровням ответственности. Как поясняет его создатель Алистер Кокберн:

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

Итак, как это применимо к бессерверным функциям?

Поскольку Алекс и его команда использовали AWS, они получили такую ​​структуру:

  • Бизнес-логика функции предоставляет несколько «портов» (или ожидает мало аргументов). Например, один для входящего события, один для постоянного хранения и один для уведомлений.
  • У них есть два адаптера для события, запускающего функцию: один для реального триггера AWS Lambda, а другой - для локального тестирования.
  • У них есть несколько переходников для постоянного хранения и уведомлений. Например, адаптер таблицы DynamoDB и адаптер в памяти.

Алекс и его команда были счастливы, что они продвигаются вперед. Но прежде чем мы продолжим, давайте посмотрим, как гексагональная архитектура влияет на каждый уровень тестовой пирамиды.

Модульное тестирование

Модульные тесты остались прежними. Но писать модульные тесты проще благодаря гексагональной архитектуре. Они могут просто использовать локальный адаптер или макет в качестве адаптера для изолированного тестирования функционального бизнес-уровня.

Интеграционное тестирование

Интеграционные тесты сильно выиграли от гексагональной архитектуры. Они смогли полностью протестировать принадлежащие им интеграции. Сторонние интеграции моделируются с другими адаптерами.

Как это работает на практике?

Каждая из их бессерверных функций имеет файлы lambda.js и main.js. Главный файл содержит бизнес-логику бессерверной функции. А файл lambda.js отвечает за подключение адаптеров и вызов файла main.js.

В основном файле есть собственные модульные и интеграционные тесты. Но его интеграционные тесты не проверяют полную интеграцию с конечными сервисами, такими как AWS S3, потому что это замедлит их работу. Вместо этого они используют адаптер в памяти для тестирования функции с интеграцией файлового хранилища.

Интеграция AWS S3 осуществляется через FileRepository, в котором есть собственные модульные и интеграционные тесты. Проверки интеграционных тестов используют AWS S3, чтобы убедиться, что конечная интеграция действительно работает.

В отличие от main.js, в файле lambda.js нет тестов, потому что в большинстве случаев он содержит всего несколько строк кода.

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

GUI тестирование

Пока Алекс и его команда создавали серверную часть приложения, уровень тестирования графического интерфейса не имел значения. Но когда они узнали больше о бессерверности, они поняли, что могут использовать ее для улучшения уровня тестирования графического интерфейса для других приложений, над которыми они работали.

UI-тесты дороги и медленны, потому что выполняются в браузере. Но бессерверный режим дешев и быстро масштабируется.

Если бы они могли запускать браузер в AWS Lambda, они бы получили дешевое распараллеливание. Это сделало бы их UI-тесты дешевле и быстрее.

Но можете ли вы запустить браузер, такой как Chrome, внутри бессерверной функции?

Да! И это легко сделать с помощью таких инструментов, как Serverless Chrome, Chromeless и Puppeteer.

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

CI / CD

Когда Алекс и его команда протестировали свою первую бессерверную функцию, пришло время развернуть код в тестовой среде. Возник новый вопрос: как они могут использовать инструменты CI / CD для развертывания своего бессерверного приложения?

Ответ прост: они могут использовать инструмент CI для запуска тестов и развертывания приложения. Для развертывания приложения используйте любой популярный инструмент, например Claudia.js, AWS SAM и Serverless Framework.

Вы по-прежнему можете использовать свой любимый инструмент CI (например, Jenkins, TravisCI или SemaphoreCI) или, если вы хотите придерживаться AWS, вы можете попробовать AWS CodeBuild.

Ручное тестирование

Даже если на ручное тестирование напрямую не влияет бессерверное тестирование, команда нашла способ улучшить свой процесс контроля качества.

Этапы и развертывание бессерверного приложения дешевы и часто быстро настраиваются. Кроме того, в бессерверном режиме вы не платите за приложение, если его никто не использует.

Это означает, что наличие среды тестирования никогда не было дешевле!

Кроме того, в бессерверном режиме вы часто можете продвигать функцию с одного этапа на другой. Это означает, что ваша команда QA может протестировать функцию, и когда они подтвердят, что она работает, вы можете продвигать ту же функцию в рабочую среду.

Помимо тестирования

Алекс и его команда отправили свою первую бессерверную функцию на предварительную подготовку, и команда была счастлива, что они научились тестировать бессерверные приложения.

Они продолжили использовать бессерверный режим в проекте и представили его в нескольких других проектах. Алекс присоединился к своим друзьям Анне и Джеффу в качестве третьего, иногда надоедливого проповедника без сервера. И жили они долго и счастливо.

Пост-сценарий

Но даже несмотря на то, что их приложение было хорошо протестировано, кое-что произошло в мгновение ока.

В результате расследования выяснилось, что одна из интеграций изменилась. Они узнали, что тестирование важно для бессерверных приложений, но этого недостаточно.

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

К счастью, с каждым днем ​​на рынке появляется все больше и больше инструментов для бессерверного мониторинга. Некоторые из хороших и популярных вариантов - IOpipe, Thundra, Dashbird и Epsagon.

Но бессерверные приложения часто имеют толстый клиент, а это означает, что внутреннего мониторинга недостаточно. Вам понадобится аналогичный инструмент для вашего интерфейса. На этом маркете тоже есть много хороших инструментов, таких как Sentry и Rollbar.

Но в духе бессерверности мы создали приложение с открытым исходным кодом для отслеживания ошибок под названием Desole. Это бессерверное приложение, которое вы можете установить в своей учетной записи AWS. Это позволяет организациям отслеживать исключения и ошибки приложений, не выбирая между удобством использования программного обеспечения как услуги и безопасностью локального решения. Вы можете проверить это здесь: https://desole.io.

Все иллюстрации созданы с помощью приложения SimpleDiagrams4.

Если вы хотите узнать больше о тестировании и создании бессерверных приложений с использованием Node.js и AWS, ознакомьтесь с книгой «Бессерверные приложения с Node.js», которую я написал вместе с Александром Симовичем для Manning Publications:



Книга расскажет вам больше о бессерверном тестировании с примерами кода, но вы также узнаете, как создать и отладить реальный бессерверный API (с базой данных и аутентификацией) с помощью Node и Claudia.js. И вы узнаете, как создавать чат-ботов для Facebook Messenger и SMS (с использованием Twilio), а также навыки работы с Alexa.