Дипломная работа: Разработка технологии непрерывного тестирования программного кода при контейнерной виртуализации на примере многопользовательского мультиплатформенного приложения

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Рис. 13. Запуск скрипта с тестами

Далее, после прохождения тестов сформированный Docker-образ развертывается в удаленном Kubernetes Cluster.

Созданная система успешно отрабатывает во всех случаях. Selenium Router, разработанный под задачи end-to-end тестирования web-приложения, работает бесперебойно за счет логики, построенной на принципе асинхронной очереди. Система гибка и может быть интегрирована в любой процесс разработки, сокращая при этом трудозатраты на сопровождение и управление процессом тестирования и развертывания приложения.

10 Разработка Backend части

Для разработки бэкенд компонента изначально был выбран язык программирования python, и web фреймворка django, в скором времени было принято решение пересмотреть язык, на котором будет разработано приложение в связи с тем, что python не отвечает основным требованиям а именно: в языке не реализован функционал позволяющий полноценно использовать многопоточность, кроме того время исполнения операций дольше чем во многих других.

После проведённого анализа был выбран язык GoLang так как он обладает самым передовым набором инструментов для параллельного исполнения кода, Go-рутины (потоки в GoLang) по сути являются rgeen-threads, что позволяет свободно использовать большое их количество без затрат процессорного времени на переключение контекста. Кроме того, этот язык продвигается корпорацией Google, что свидетельствует о его качестве, и о том, что язык продолжит развиваться и совершенствоваться. Разработка приложения производилась в несколько этапов.

10.1 Проектирование

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

Роутер: данный слой отвечает за роутинг всех входящих запросов на конкретные эндпоинты;

Middleware - Слой в котором производится предобработка входящих данных, их анализ и валидация;

API слой - Слой производящий мапинг входящих данных и передачу их на более нижние уровни, а также за обработку результатов функций нижних уровней и формировании http ответа на клиент;

Services- слой, реализующий всю бизнес логику проекта;

Store - слой, отвечающий за хранение всех необходимых данных.

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

Взаимодействие между слоями:

middleware: передает информацию в API слой;

API: получает информацию от Middlewares, передает на сервисный слой, затем проанализировав результаты возвращает их на Клиент-компонент приложения;

Services: получает информацию от API, передает информацию слою Store и различным сторонним сервисам, и обрабатывает ответ от них, передавая результаты анализа его на слой API;

Store: получает информацию от сервисного слоя, выполняет запрос к базе данных и возвращает их на слой Services.

Кроме того, на этом этапе была выбрана база данных MySQL, решение было принято в связи с популярностью данной бд и доступностью документации к ней, так же MySQL обладает рядом инструментов отсутствующих в аналогах (PostGreSQL, SQLite, MsSQL), таких как хинты и кроссплатформенность. После этого необходимо было разработать интерфейс общения между клиентом и сервером, так как SOAP является специфичным а XML устарел было принято решение использовать для передачи информации JSON, за его читабельность, ёмкость, и удобство в использовании (поддерживается на всех языках на которых написаны компоненты приложения) .

Рис. 14. Архитектура backend компонента приложения

10.2 Разработка

После проектирования была проведена разработка в соответствии с принципами разработки SOLID (single responsibility, open-closed, Liskov substitution, interface segregation и dependency inversion). Согласно первому принципу каждая сущность в проекте должна иметь своё элементарное предназначение, например запись в файл, произведение сетевого взаимодействия и тд.

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

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

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

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

10.3 Развёртка

Для развёртывания был выбран сервер, предоставленный компании amazon, но с ним возникло множество проблем: главной из них стала проблема частых сбоев с доступом к серверу с территории РФ, проблема решилась после неоднократной смены IP адреса.

Кроме того, единственная компания, предоставляющая инструмент для самостоятельного получения валидных TLS сертификатов, включила большинство стандартных доменных имен, соответствующих amazon E2C серверам, предоставляемым клиентам для размещения и развёртывания приложений в черный список, решить эту проблему удалось только зарегистрировав собственное доменное имя.

После решения вышеупомянутых проблем на сервере была настроена необходимая экосистема, доставлен исполняемый файл backend компонента приложения и произведен его запуск

10.4 Разработка алгоритма непрерывного тестирования кода

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

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

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

Для того чтоб финальный алгоритм был удобным в использовании он должен обладать главным необходимым качеством: он не должен отнимать время у разработчика и отвлекать его от непосредственной работы (написании кода). Поэтому было принято решение инициализировать запуск тестов основываясь на взаимодействии разработчиков с их VCS (система контроля версий, их используют 90% разработчиков при работе над проектами, ярчайшим и наиболее популярным примером считается GIT VCS), в таком случае это не будет требовать от пользователя каких либо лишних действий при разработке и не будет его отвлекать.

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

В случае же удачного прохождения тестов актуальный код необходимо перекомпилировать, используя конфигурацию площадки, на которой впоследствии будет происходить развёртывание. Затем необходимо записать новый слой поверх исходного Docker образа, доставить образ на площадку и развернуть его там, после чего настроить ОС площадки(пробросить соответствующие порты до портов контейнера), в случае любых ошибок нужно информировать о них (ошибках) разработчика, так же как и в случае с успешным выполнением сценария.

Рис. 15. Алгоритм действий системы.

10.5 Написание тестов

Для кода исходного приложения были написаны всевозможные тесты, для серверной части приложения в клиент-серверной модели существуют следующие виды тестов:

Юнит тесты-тесты задача которых проверить работоспособность отдельных базовых функций и методов сущностей, подобными тестами необходимо обкладывать 70-100% соответствующих функций они помогают выявлять банальные ошибки такие как перепутанные имена переменных, использование неправильных математических операторов и базовых операторов языка.

Object тесты-с помощью них выявляются ошибки в работоспособности той или иной сущности проекта, причем если сущность содержит в себе поля также являющиеся сущностями то во время тестирования сущности верхнего уровня их имплементации необходимо заменить тестовыми имплементациями, разработанными так, что их работоспособность будет стопроцентной и не повлияет на результат тестирования сущности полем которой они являются. Для эффективного тестирования область покрытия сущностей проекта подобными тестами должна быть свыше 90%.

API тесты предназначены для тестирования пользовательских сценариев, в режиме подобного тестирования необходимо заменить тестовыми имплементациями лишь те сущности проекта работоспособность которых не зависит непосредственно от разработчика (интеграторы сторонних сервисов, сущности, отвечающие за обращение к базам данных и тд.). Данная группа тестов затрагивает несколько слоёв приложения и выявляет ошибка в их взаимодействии, если зона покрытия проекта API-тестами меньше 90% результаты тестирования нельзя считать актуальными.

Интеграционные тесты, особенность этих тестов в том что они проверяют интеграцию чего бы то ни было в проект, поэтому важно писать их с учетом всевозможных отказов объектов и способов их интеграции (ошибка на стороннем сервере, отказ сетевого взаимодействия, падение движка базы данных), тесты помогают своевременно выявить неработоспособность интегрируемых сервисов и отключить связанный с ними функционал приложения. Если не обложить тестами 100% сущностей, отвечающих за интеграцию то возникает большая вероятность потери части функционала системы и введение ее пользователей в заблуждение.

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

Так как приложение написано на GoLang для написания тестов был использован фреймворк “Go test”.

10.6 Запуск системы

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

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

11 Результат работы

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

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