Automatiséiert Testen vu Mikroservicer am Docker fir kontinuéierlech Integratioun

An Projeten am Zesummenhang mat der Entwécklung vun microservice Architektur, CI / CD Plënneren aus der Kategorie vun enger agreabel Geleeënheet fir d'Kategorie vun enger dréngend Noutwennegkeet. Automatiséiert Testen ass en integralen Deel vun der kontinuéierlecher Integratioun, eng kompetent Approche fir déi d'Equipe vill agreabel Owender mat Famill a Frënn ginn. Soss riskéiert de Projet ni fäerdeg ze ginn.

Et ass méiglech de ganze Mikroservicecode mat Eenheetstester mat Spottobjekter ze decken, awer dëst léist de Problem nëmmen deelweis a léisst vill Froen a Schwieregkeeten, besonnesch wann d'Aarbecht mat Daten testen. Wéi ëmmer sinn déi dréngendsten d'Datekonsistenz an enger relationaler Datebank ze testen, d'Aarbecht mat Cloud Servicer ze testen, a falsch Viraussetzungen ze maachen wann Dir Spottobjekter schreift.

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

Automatisatioun vun dëser Approche stellt eng Rei vu Probleemer, d'Léisung fir déi hei ënnen beschriwwe gëtt:

  • Konflikter vun parallel Aufgaben am selwechten Docker Host;
  • Identifizéierer Konflikter an der Datebank während Test Iteratiounen;
  • ожидание готовности микросервисов;
  • Fusioun an erausginn Logbicher op extern Systemer;
  • тестирование исходящих HTTP-запросов;
  • Web Socket Testen (mat SignalR);
  • OAuth Authentifikatioun an Autorisatioun testen.

Dësen Artikel baséiert op meng Ried bei SECR 2019. Also fir déi, déi ze faul sinn fir ze liesen, hei ass eng Opnam vun der Ried.

Automatiséiert Testen vu Mikroservicer am Docker fir kontinuéierlech Integratioun

В статье я расскажу, как при помощи скрипта запустить в Docker тестируемый сервис, базу данных и сервисы Amazon AWS, затем тесты на Postman и после их завершения остановить и удалить созданные контейнеры. Тесты выполняются при каждом изменении кода. Таким образом, мы убеждаемся, что каждая версия корректно работает с базой данных и сервисами AWS.

Datselwecht Skript gëtt souwuel vun den Entwéckler selwer op hiren Windows Desktops wéi och vum Gitlab CI Server ënner Linux lafen.

Fir gerechtfäerdegt ze sinn, d'Aféierung vun neien Tester däerf net d'Installatioun vun zousätzlech Tools erfuerderen entweder um Computer vum Entwéckler oder um Server wou d'Tester op engem Verpflichtung lafen. Docker léist dëse Problem.

Тест должен работать на локальном сервере по следующим причинам:

  • D'Netz ass ni komplett zouverlässeg. Vun dausend Ufroe kann een ausfalen;
    An dësem Fall wäert den automateschen Test net funktionnéieren, d'Aarbecht stoppt, an Dir musst de Grond an de Logbicher kucken;
  • Ze heefeg Ufroe sinn net vun e puer Drëtt Partei Servicer erlaabt.

Zousätzlech ass et net wënschenswäert de Stand ze benotzen well:

  • E Stand kann net nëmmen duerch schlecht Code gebrach ginn, awer och duerch Donnéeën déi de richtege Code net veraarbecht kann;
  • Egal wéi schwéier mir probéieren all d'Ännerungen, déi vum Test während dem Test selwer gemaach goufen, zréckzekréien, eppes ka falsch goen (soss, firwat Test?).

Iwwer de Projet a Prozessorganisatioun

Eis Firma huet eng Mikroservice Webapplikatioun entwéckelt, déi am Docker an der Amazon AWS Cloud leeft. Eenheetstester goufe schonn um Projet benotzt, awer Feeler sinn dacks geschitt, déi d'Eenheetstester net entdeckt hunn. Et war néideg fir e ganze Mikroservice zesumme mat der Datebank an Amazon Servicer ze testen.

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

Архитектура проекта

Automatiséiert Testen vu Mikroservicer am Docker fir kontinuéierlech Integratioun

Приложение состоит из более чем десяти сервисов. Некоторые из них написаны на .NET Core, а некоторые на NodeJs. Каждый сервис работает в Docker-контейнере в Amazon Elastic Container Service. У каждого своя база Postgres, а у некоторых еще и Redis. Общих баз нет. Если нескольким сервисам нужны одни и те же данные, то эти данные в момент их изменения передаются каждому из этих сервисов через SNS (Simple Notification Service) и SQS (Amazon Simple Queue Service), и сервисы сохраняют их в свои обособленные базы.

SQS и SNS

SQS erlaabt Iech Messagen an eng Schlaang ze setzen an Messagen aus der Schlaang ze liesen mat dem HTTPS Protokoll.

Wann e puer Servicer eng Schlaang liesen, da kënnt all Message nëmmen un ee vun hinnen. Dëst ass nëtzlech wann Dir e puer Instanzen vum selwechte Service leeft fir d'Laascht tëscht hinnen ze verdeelen.

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

An SNS erstellt Dir en Thema an abonnéiert Iech op, zum Beispill eng SQS Schlaang. Dir kënnt Messagen op Thema schécken. An dësem Fall gëtt de Message un all Schlaang geschéckt, déi op dëst Thema abonnéiert ass. SNS huet keng Method fir Messagen ze liesen. Wann Dir während Debugging oder Tester musst erausfannen wat op SNS geschéckt gëtt, kënnt Dir eng SQS-Schlaang erstellen, se op dat gewënschte Thema abonnéieren an d'Schlaang liesen.

Automatiséiert Testen vu Mikroservicer am Docker fir kontinuéierlech Integratioun

API Gateway

Déi meescht Servicer sinn net direkt vum Internet zougänglech. Zougang ass iwwer API Gateway, déi Zougangsrechter iwwerpréift. Dëst ass och eise Service, an et ginn och Tester dofir.

Echtzäit Notifikatiounen

Приложение использует Signal Rfir Echtzäit Notifikatiounen dem Benotzer ze weisen. Dëst gëtt am Notifikatiounsservice ëmgesat. Et ass direkt vum Internet zougänglech a selwer funktionnéiert mat OAuth, well et onpraktesch erausgestallt gouf fir Ënnerstëtzung fir Web Sockets an Gateway ze bauen, am Verglach mat der Integratioun vun OAuth an den Notifikatiounsservice.

Gutt-bekannt Test Approche

Eenheetstester ersetzen Saachen wéi d'Datebank mat Spottobjekter. Wann e Mikroservice, zum Beispill, probéiert e Rekord an enger Tabell mat engem auslännesche Schlëssel ze kreéieren, an de Rekord, dee vun deem Schlëssel referenzéiert gëtt, existéiert net, da kann d'Ufro net ausgefouert ginn. Eenheetstester kënnen dëst net erkennen.

В статье от Microsoft Et gëtt proposéiert eng In-Memory Datebank ze benotzen an Spottobjekter ëmzesetzen.

In-Memory Datebank ass eng vun den DBMSen ënnerstëtzt vum Entity Framework. Et gouf speziell fir Testen erstallt. D'Donnéeën an esou enger Datebank ginn nëmme gespäichert bis de Prozess deen se benotzt ophält. Et erfuerdert keng Tabellen ze kreéieren an d'Datenintegritéit iwwerpréift.

Mock Objete modelléieren d'Klass, déi se ersetzen, nëmme souwäit den Testentwéckler versteet wéi et funktionnéiert.

Wéi Dir Postgres kritt fir automatesch Migratiounen unzefänken an auszeféieren wann Dir en Test leeft ass net am Microsoft Artikel spezifizéiert. Meng Léisung mécht dëst an, zousätzlech, füügt kee Code speziell fir Tester un de Mikroservice selwer.

Переходим к решению

Während dem Entwécklungsprozess gouf et kloer datt d'Eenheetstester net genuch waren fir all Probleemer fristgerecht ze fannen, sou datt et decidéiert gouf dëst Thema aus engem anere Wénkel unzegoen.

Ariichten vun engem Test Ëmfeld

Déi éischt Aufgab ass en Testëmfeld z'installéieren. Schrëtt néideg fir e Mikroservice ze lafen:

  • Настроить тестируемый сервис на локальное окружение, в переменных окружения указываются реквизиты для подключения к базе и AWS;
  • Start Postgres a maacht d'Migratioun andeems Dir Liquibase leeft.
    A relationalen DBMSen, ier Dir Daten an d'Datebank schreift, musst Dir en Dateschema erstellen, an anere Wierder, Dëscher. Beim Aktualiséierung vun enger Applikatioun mussen d'Dëscher op d'Form bruecht ginn, déi vun der neier Versioun benotzt gëtt, an am léifsten ouni Daten ze verléieren. Dëst gëtt Migratioun genannt. D'Erstelle vun Dëscher an enger ursprénglech eidel Datebank ass e spezielle Fall vu Migratioun. Migratioun kann an der Applikatioun selwer agebaut ginn. Béid .NET an NodeJS hunn Migratiounskader. An eisem Fall, aus Sécherheetsgrënn, sinn Mikroservicer d'Recht entzunn fir den Dateschema z'änneren, an d'Migratioun gëtt mat Liquibase gemaach.
  • Запустить Amazon LocalStack. Это реализация сервисов AWS для запуска у себя. Для LocalStack есть готовый образ в Docker Hub.
  • Run de Skript fir déi néideg Entitéiten am LocalStack ze kreéieren. Shell Scripte benotzen den AWS CLI.

Benotzt fir Testen op de Projet Bréifdréier. Et gouf et virdru, awer et gouf manuell lancéiert an eng Applikatioun getest déi schonn um Stand agesat gouf. Dëst Tool erlaabt Iech arbiträr HTTP(S) Ufroen ze maachen an z'iwwerpréiwen ob d'Äntwerten d'Erwaardungen entspriechen. Ufroe ginn an eng Sammlung kombinéiert, an déi ganz Sammlung ka lafen.

Automatiséiert Testen vu Mikroservicer am Docker fir kontinuéierlech Integratioun

Как устроен автоматический тест

Wärend dem Test funktionnéiert alles am Docker: de Service ënner Test, Postgres, de Migratiounstool, a Postman, oder éischter seng Konsolversioun - Newman.

Docker léist eng Rei vu Probleemer:

  • Независимость от конфигурации хоста;
  • Установка зависимостей: докер скачивает образы с Docker Hub;
  • Возврат системы в исходное состояние: просто удаляем контейнеры.

Docker-komponéieren Vereenegt Container an e virtuellt Netzwierk, isoléiert vum Internet, an deem Container sech duerch Domain Nimm fannen.

Тестом управляет shell-скрипт. Для запуска теста под Windows используем git-bash. Таким образом, достаточно одного скрипта и для Windows и для Linux. Git и Docker установлены у всех разработчиков на проекте. При установке Git под Windows устанавливается git-bash, так что он тоже у всех есть.

Скрипт выполняет следующие шаги:

  • Построение докер-образов
    docker-compose build
  • Lancéiere vun der Datebank a LocalStack
    docker-compose up -d <контейнер>
  • Миграция БД и подготовка LocalStack
    docker-compose run <контейнер>
  • Запуск тестируемого сервиса
    docker-compose up -d <сервис>
  • Den Test lafen (Newman)
  • Stoppen all Container
    docker-compose down
  • Постинг результатов в Slack
    Mir hunn en Chat wou Messagen mat engem grénge Scheckzeechen oder engem roude Kräiz an e Link op de Logbuch goen.

Déi folgend Docker Biller sinn an dëse Schrëtt involvéiert:

  • De Service deen getest gëtt ass datselwecht Bild wéi fir d'Produktioun. D'Konfiguratioun fir den Test ass duerch Ëmfeldvariablen.
  • Fir Postgres, Redis a LocalStack gi fäerdeg Biller vum Docker Hub benotzt. Et ginn och fäerdeg Biller fir Liquibase an Newman. Mir bauen eis op hirem Skelett, dobäi eis Fichieren do.
  • Fir LocalStack virzebereeden, benotzt Dir e fäerdeg AWS CLI Bild an erstellt e Bild mat engem Skript op der Basis.

Benotzen Bänn, Dir musst net en Docker-Bild bauen just fir Dateien an de Container ze addéieren. Wéi och ëmmer, Volumen sinn net gëeegent fir eis Ëmwelt well Gitlab CI Aufgaben selwer a Container lafen. Dir kënnt Docker vu sou engem Container kontrolléieren, awer Volumen montéieren nëmmen Ordner vum Hostsystem, an net vun engem anere Container.

Themen déi Dir kënnt stousse

Waarden op Bereetschaft

Wann e Container mat engem Service leeft, heescht dat net datt et prett ass fir Verbindungen ze akzeptéieren. Dir musst op d'Verbindung waarden fir weiderzekommen.

Dëse Problem gëtt heiansdo mat engem Skript geléist wait-fir-it.sh, déi op eng Geleeënheet waart fir eng TCP Verbindung ze etabléieren. Wéi och ëmmer, LocalStack kann e 502 Bad Gateway Feeler werfen. Ausserdeem besteet et aus ville Servicer, a wann ee vun hinnen prett ass, seet dat näischt iwwer déi aner.

Decisioun: LocalStack Provisioning Scripten déi op eng 200 Äntwert vu béid SQS an SNS waarden.

Parallel Aufgab Konflikter

Несколько тестов могут работать одновременно в одном Docker-хосте, поэтому имена контейнеров и сетей должны быть уникальны. Более того, тесты с разных веток одного сервиса тоже могут работать одновременно, поэтому недостаточно прописать в каждом compose-файле свои имена.

Decisioun: De Skript setzt d'Variabel COMPOSE_PROJECT_NAME op en eenzegaartege Wäert.

Особенности Windows

Et ginn eng Rei Saachen, déi ech wëll drop hiweisen wann Dir Docker op Windows benotzt, well dës Erfarunge wichteg sinn fir ze verstoen firwat Feeler optrieden.

  1. Shell Scripten an engem Container mussen Linux Linnenendungen hunn.
    De Shell CR Symbol ass e Syntaxfehler. Et ass schwéier aus der Fehlermeldung ze soen datt dëst de Fall ass. Wann Dir esou Scripten op Windows ännert, brauch Dir e richtegen Texteditor. Zousätzlech muss de Versiounskontrollsystem richteg konfiguréiert sinn.

Dëst ass wéi git konfiguréiert ass:

git config core.autocrlf input

  1. Git-bash emuléiert Standard Linux Classeure an, wann Dir eng exe Datei rufft (inklusiv docker.exe), ersetzt absolute Linux Weeër mat Windows Weeër. Allerdéngs mécht dëst kee Sënn fir Weeër net op der lokaler Maschinn (oder Weeër an engem Container). Dëst Verhalen kann net behënnert ginn.

Decisioun: füügt en zousätzleche Slash un den Ufank vum Wee un: //bin amplaz /bin. Linux versteet esou Weeër; dofir sinn e puer Slashes d'selwecht wéi een. Awer git-bash erkennt sou Weeër net a probéiert se net ze konvertéieren.

Logausgang

Wann Dir Tester leeft, géif ech gär Logbicher vu Newman an dem Service gesinn, dee getest gëtt. Zënter datt d'Evenementer vun dëse Logbicher matenee verbonne sinn, ass et vill méi praktesch ze kombinéieren an enger Konsole wéi zwee separat Dateien. Newman lancéiert via docker-komponéieren lafen, a sou datt seng Ausgang an der Konsole endet. Alles wat bleift ass sécher ze stellen datt d'Ausgab vum Service och dohinner geet.

Первоначальное решение состояло в том, чтобы делать Docker-Kompositioun kee Fändel -d, awer mat de Shell-Fäegkeeten, schéckt dëse Prozess op den Hannergrond:

docker-compose up <service> &

Dëst huet geschafft bis et néideg war Logbicher vum Docker un en Drëtt Partei Service ze schécken. Docker-Kompositioun gestoppt Logbicher op d'Konsol erausginn. Allerdéngs huet d'Equipe geschafft Docker bäitrieden.

Decisioun:

docker attach --no-stdin ${COMPOSE_PROJECT_NAME}_<сервис>_1 &

Identifikateur Konflikt während Test Iteratiounen

Tester ginn a verschiddenen Iteratiounen ausgefouert. D'Datebank ass net geläscht. Records an der Datebank hunn eenzegaarteg IDen. Wa mir spezifesch IDen an Ufroen opschreiwen, kréie mir e Konflikt bei der zweeter Iteratioun.

Fir et ze vermeiden, mussen entweder d'IDen eenzegaarteg sinn, oder all Objeten, déi vum Test erstallt goufen, mussen geläscht ginn. E puer Objete kënnen net wéinst Ufuerderunge geläscht ginn.

Decisioun: Generéiere GUIDs mat Postman Scripten.

var uuid = require('uuid');
var myid = uuid.v4();
pm.environment.set('myUUID', myid);

Затем в запросе использовать символ {{myUUID}}, déi mam Wäert vun der Variabel ersat gëtt.

Взаимодействие через LocalStack

Wann de Service deen getest gëtt, liest oder schreift an eng SQS Schlaang, dann fir dëst z'iwwerpréiwen, muss den Test selwer och mat dëser Schlaang schaffen.

Decisioun: запросы из Postman к LocalStack.

API сервисов AWS документировано, что позволяет делать запросы без SDK.

Wann e Service an eng Schlaang schreift, da liesen mir et a kontrolléieren den Inhalt vun der Noriicht.

Если сервис отправляет сообщения в SNS, на этапе подготовки LocalStack создается еще и очередь и подписывается на этот SNS-топик. Дальше все сводится к описанному выше.

Wann de Service muss e Message aus der Schlaang liesen, dann am virege Test Schrëtt schreiwen mir dëse Message un d'Schlaang.

Тестирование HTTP-запросов, исходящих от тестируемого микросервиса

E puer Servicer funktionnéieren iwwer HTTP mat eppes anescht wéi AWS, an e puer AWS Funktiounen ginn net am LocalStack implementéiert.

Decisioun: в этих случаях может помочь MockServer, déi e fäerdeg Bild an DockerHub. Erwaart Ufroen an Äntwerten op si ginn duerch eng HTTP-Ufro konfiguréiert. D'API ass dokumentéiert, also maache mir Ufroe vum Postman.

Тестирование аутентификации и авторизации OAuth

Mir benotzen OAuth an JSON Web Tokens (JWT). Den Test erfuerdert en OAuth Provider dee mir lokal kënne lafen.

All Interaktioun tëscht dem Service an dem OAuth Provider kënnt op zwou Ufroen erof: als éischt gëtt d'Konfiguratioun gefrot /.bekannt/openid-configuration, an dann gëtt den ëffentleche Schlëssel (JWKS) op der Adress vun der Konfiguratioun gefrot. All dëst ass statesch Inhalt.

Decisioun: наш тестовый OAuth-провайдер – это сервер статического контента и два файла на нем. Токен сгенерирован один раз и закоммичен в Git.

Особенности тестирования SignalR

С веб-сокетами Postman не работает. Для тестирования SignalR был создан специальный инструмент.

E SignalR Client ka méi sinn wéi just e Browser. Et gëtt eng Clientsbibliothéik fir et ënner .NET Core. De Client, geschriwwen an .NET Core, mécht eng Verbindung, gëtt authentifizéiert a waart op eng spezifesch Sequenz vu Messagen. Wann en onerwaarte Message kritt oder d'Verbindung verluer ass, geet de Client eraus mat engem Code vun 1. Wann déi lescht erwaart Noriicht opgeholl gëtt, geet de Client eraus mat engem Code vun 0.

Одновременно с клиентом работает Newman. Клиентов запускается несколько, чтобы проверить, что сообщения доставляются всем, кому надо.

Automatiséiert Testen vu Mikroservicer am Docker fir kontinuéierlech Integratioun

Fir verschidde Clienten ze lafen benotzt d'Optioun -- Skala в командной строке docker-compose.

Ier Dir leeft, waart de Postman Skript op all Cliente fir Verbindungen opzebauen.
Проблема ожидания соединения нам уже встречалась. Но там были серверы, а здесь клиент. Нужен другой подход.

Decisioun: de Client am Container benotzt de Mechanismus HealthCheckfir de Skript um Host iwwer säi Status z'informéieren. De Client erstellt eng Datei op engem spezifesche Wee, sot /healthcheck, soubal d'Verbindung etabléiert ass. De HealthCheck Skript an der Docker Datei gesäit esou aus:

HEALTHCHECK --interval=3s CMD if [ ! -e /healthcheck ]; then false; fi

Equipe docker Inspektioun показывает для контейнера обычный статус, health-статус и код завершения.

Nodeems Newman fäerdeg ass, kontrolléiert de Skript datt all Container mam Client ofgeschloss sinn, mam Code 0.

Happinnes existéiert

Nodeems mir d'Schwieregkeeten uewe beschriwwen iwwerwonnen hunn, hu mir e Set vu stabile Lafentester. An Tester funktionnéiert all Service als eenzeg Eenheet, interagéiert mat der Datebank an Amazon LocalStack.

Dës Tester schützen en Team vun 30+ Entwéckler vu Feeler an enger Applikatioun mat komplexer Interaktioun vun 10+ Mikroservicer mat heefeg Deployementer.

Source: will.com

Setzt e Commentaire