{"id":7474,"date":"2021-05-17T15:39:49","date_gmt":"2021-05-17T15:39:49","guid":{"rendered":"https:\/\/berg-software.com\/einblicke\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/"},"modified":"2021-05-17T15:45:08","modified_gmt":"2021-05-17T15:45:08","slug":"end-to-end-tests-reise-integration-in-eine-gitlab-pipeline","status":"publish","type":"post","link":"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/","title":{"rendered":"End-to-End-Tests Reise &amp; Integration in eine GitLab-Pipeline"},"content":{"rendered":"<p>[et_pb_section fb_built=&#8220;1&#8243; fullwidth=&#8220;on&#8220; _builder_version=&#8220;4.4.1&#8243;][et_pb_fullwidth_post_title meta=&#8220;off&#8220; featured_placement=&#8220;background&#8220; _builder_version=&#8220;4.6.6&#8243; title_font=&#8220;||||||||&#8220; title_text_color=&#8220;#ff6317&#8243; title_font_size=&#8220;3.5em&#8220; meta_font=&#8220;|300|||||||&#8220; meta_text_color=&#8220;#ffffff&#8220; meta_font_size=&#8220;1em&#8220; background_enable_color=&#8220;off&#8220; use_background_color_gradient=&#8220;on&#8220; background_color_gradient_start=&#8220;rgba(248,248,248,0.85)&#8220; background_color_gradient_end=&#8220;rgba(248,248,248,0.75)&#8220; background_color_gradient_overlays_image=&#8220;on&#8220; min_height=&#8220;20vh&#8220; height=&#8220;400px&#8220; custom_padding=&#8220;6vh||6vh||false|false&#8220; global_module=&#8220;403&#8243; locked=&#8220;off&#8220;][\/et_pb_fullwidth_post_title][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.7.7&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; hover_enabled=&#8220;0&#8243; border_color_left=&#8220;#ff6317&#8243; sticky_enabled=&#8220;0&#8243;]<\/p>\n<h2>Einf\u00fchrung in End-to-End Tests &amp; GitLab-Integration<\/h2>\n<p>W\u00e4hrend unserer Microservices Reise in den letzten Jahren sind wir bei der Entwicklung, Wartung und Integration der End-to-End Tests in unsere CI\/CD-Pipeline auf mehrere Probleme gesto\u00dfen. Schauen wir uns die wichtigsten Themen an, auf die wir gesto\u00dfen sind, und &#8211; wo ist der Fall &#8211; wie wir sie gel\u00f6st haben:<\/p>\n<ul>\n<li><a href=\"#Whatareendtoendtests\" title=\"Go to: What are end-to-end tests?\">Was sind End-to-End Tests?<\/a><\/li>\n<li><a href=\"#Whywriteendtoendtests\" title=\"Go to: Why do we need to write end-to-end tests?\">Warum m\u00fcssen wir End-to-End-Tests schreiben?<\/a><\/li>\n<li><a href=\"#Whentowriteendtoendtests\" title=\"Go to: When to write end to end tests?\">Wann sollte man End-to-End-Tests schreiben?<\/a><\/li>\n<li><a href=\"#Howmuchtesttowrite\" title=\"Go to: How much end-to-end test to write?\">Wie viel End-to-End Test zu schreiben?<\/a><\/li>\n<li><a href=\"#GitLabbasics\" title=\"Go to: GitLab basics\">GitLab Grundlagen<\/a><\/li>\n<li><a href=\"#Howtosetuptherunnersandcaching\" title=\"Go to: How to: set up the runners and caching\">So geht&#8217;s: einrichten der Runner und Caching<\/a><\/li>\n<li><a href=\"#Howtosetupthepipeline\" title=\"Go to: How to: set up the pipeline\">So geht&#8217;s: einrichten der Pipeline<\/a><\/li>\n<li><a href=\"#Howtoisolatethetests\" title=\"Go to: How to: isolate the tests\">So geht&#8217;s: isolieren die Tests<\/a><\/li>\n<li><a href=\"#Howtopreparetheenvironmentforrunningthetests\" title=\"Go to: How to: Prepare the environment for running the tests\">So geht&#8217;s: vorbereiten der Umgebung f\u00fcr die Durchf\u00fchrung der Tests<\/a><\/li>\n<li><a href=\"#Howtopreparethedataforthetests\" title=\"Go to: How to: prepare the data for the tests\">So geht&#8217;s: bereiten die Daten f\u00fcr die Tests<\/a><\/li>\n<li><a href=\"#Howtorunthetestswithdockercompose\" title=\"Go to: How to: run the tests with Docker Compose\">So geht&#8217;s: ausf\u00fchren der Tests mit Docker Compose<\/a><\/li>\n<li><a href=\"#Howtocleanupafterthetests\" title=\"Go to: How to: clean up after the tests\">So geht&#8217;s: aufr\u00e4umen nach den Tests<\/a><\/li>\n<li><a href=\"#Howtomakethetestsasfastaspossible\" title=\"Go to: How to: make the tests as fast as possible\">So geht&#8217;s: die Tests so schnell wie m\u00f6glich zu machen<\/a><\/li>\n<li><a href=\"#Howtomaintainthetestsuite\" title=\"Go to: How to: maintain the test suite\">So geht&#8217;s: Wartung der Testsuite<\/a><\/li>\n<li><a href=\"#Conclusions\" title=\"Go to: Conclusions\">Fazit<\/a><\/li>\n<\/ul>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2>Voraussetzungen<\/h2>\n<p>Um diesen Artikel optimal nutzen zu k\u00f6nnen, ist zumindest ein Grundverst\u00e4ndnis von Linux, Docker und Docker Compose erforderlich.<\/p>\n<p>In diesem Artikel wird davon ausgegangen, dass alle Microservices als Docker-Images gepackt und in einem privaten oder \u00f6ffentlichen Docker-Repository ver\u00f6ffentlicht werden.<\/p>\n<p>Das End-to-End-Testframework muss Junit-\u00e4hnliche Runner unterst\u00fctzen, die von Gradle, Maven oder der Befehlszeile aus gestartet werden k\u00f6nnen.<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row column_structure=&#8220;1_2,1_2&#8243; use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;1_2&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2>Kontext<\/h2>\n<p>Die Beispielsoftware ist eine Unternehmensanwendung, die auf dem Java Tech Stack mit Spring Boot im Backend und Angular im Frontend entwickelt wurde. Das System besteht aus mehreren Microservices, die in der Open Telekom Cloud als Docker-Container bereitgestellt werden. Wir verwenden Hazelcast als Integrations-Backbone und MySql als persistenten Storage.<\/p>\n<p>Da es mehrere Umgebungen gibt, haben wir eine GitLab-Pipeline f\u00fcr die kontinuierliche Integration und Bereitstellung eingerichtet. Wir haben eine konsistente Testsuite entwickelt, die aus Unit-Tests, Integrationstests, Sicherheitstests, Leistungstests und End-to-End-Tests besteht. Die meisten von ihnen werden bei jedem Zusammenf\u00fchren auf unseren Umgebungszweigen ausgef\u00fchrt. Wir arbeiten mit Feature-Zweigen, die in die Environment-Zweigen zusammengef\u00fchrt werden. Es gibt im Grunde f\u00fcnf Umgebungen, zwei Entwicklungssysteme, ein Feature-Preview-System, ein Staging-System und die Produktionsumgebung.<\/p>\n<p>Als End-to-End-Testframework setzen wir Serenity ein, weil es starke Unterst\u00fctzung f\u00fcr automatisierte Tests mit Selenium 2 bietet. Der Zweck von Serenity ist es, eine lebendige Dokumentation zu erstellen. Die Tests sind im &#8220; give &#8211; when &#8211; then&#8220;-Stil geschrieben und liefern illustrierte, narrative Berichte.<\/p>\n<p>Die aggregierten Berichte k\u00f6nnen anhand von Features, Stories, Steps, Szenarien und Tests organisiert werden.[\/et_pb_text][\/et_pb_column][et_pb_column type=&#8220;1_2&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-01-Interaction-journey.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 01 Interaction journey&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 01 Interaction journey&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;4vh|||2vw|false|false&#8220;][\/et_pb_image][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-02-Test-count.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 02 Test count&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 02 Test count&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;4vh|||2vw|false|false&#8220;][\/et_pb_image][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row column_structure=&#8220;1_2,1_2&#8243; use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;1_2&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Whatareendtoendtests\">Was sind End-to-End Tests?<\/h2>\n<p>End-to-End-Tests sind im Grunde User-Interface Tests. Sie befinden sich an der Spitze der Testpyramide und sind die teuersten zu entwickeln und zu warten, aber die langsamsten auszuf\u00fchren. Daher besteht nur ein kleiner Prozentsatz der gesamten Testsuite aus End-to-End-Tests.[\/et_pb_text][\/et_pb_column][et_pb_column type=&#8220;1_2&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-03-End-to-end-tests-pyramid.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 03 End-to-end tests pyramid&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 03 End-to-end tests pyramid&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;4vh|||2vw|false|false&#8220;][\/et_pb_image][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Whywriteendtoendtests\">Warum m\u00fcssen wir End-to-End-Tests schreiben?<\/h2>\n<p>Die End-to-End-Tests sind ein Sicherheitsnetz f\u00fcr Refactoring und kontinuierliche Erweiterungen. Sie erh\u00f6hen die Softwarequalit\u00e4t, indem sie fr\u00fcher Feedback geben, bevor sie in Die Produktion gehen.<\/p>\n<p>Nicht zuletzt sind End-to-End-Tests eine Notwendigkeit, weil sie das Vertrauen des Teams in jede Lieferung erh\u00f6hen.<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Whentowriteendtoendtests\">Wann sollte man End-to-End-Tests schreiben?<\/h2>\n<p>Manchmal sind Unit-Tests schwer zu implementieren oder anzufangen, insbesondere bei Legacy-Anwendungen, bei denen ein Refactoring erforderlich ist, um den Code testbarer zu machen. In diesem Fall ist es sicherer, mit End-to-End-Tests zu beginnen.<\/p>\n<p>Dar\u00fcber hinaus k\u00f6nnen die End-to-End-Tests auch als Abnahmetests verwendet werden. Wenn die UI-Mockups \u00fcbersichtlich sind, k\u00f6nnen sie parallel zur Story-Implementierung geschrieben werden.<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row column_structure=&#8220;1_2,1_2&#8243; use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;1_2&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howmuchtesttowrite\">Wie viel End-to-End Test zu schreiben?<\/h2>\n<p>Die End-to-End-Tests sollten nur bei gesch\u00e4ftskritischen User Journeys durchgef\u00fchrt werden. Es m\u00fcssen nur gl\u00fcckliche Pfade eingeschlossen werden, d. h., wir m\u00fcssen die Fehlerf\u00e4lle oder die Validierungen nicht testen.[\/et_pb_text][\/et_pb_column][et_pb_column type=&#8220;1_2&#8243; _builder_version=&#8220;4.4.1&#8243;][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"GitLabbasics\">GitLab Grundlagen<\/h2>\n<p>GitLab ist die Wahl von Berg Software f\u00fcr das Hosting des Source Codes und den Betrieb der kontinuierlichen Integrations- und Delivery-Pipelines. Die Pl\u00e4ne reichen von kostenlos bis Enterprise. Sie k\u00f6nnen private oder \u00f6ffentliche Repositorys erstellen.<\/p>\n<p>Einige der sch\u00f6nsten Out-of-Box-Funktionen von GitLab sind:<\/p>\n<ul>\n<li>REST APIs<\/li>\n<li>CI\/CD-Unterst\u00fctzung<\/li>\n<li>protected branches<\/li>\n<li>Code-Review-Unterst\u00fctzung<\/li>\n<li>vordefinierte Variablen<\/li>\n<li>custom runners-Unterst\u00fctzung<\/li>\n<li>Integration mit verschiedenen identity providers<\/li>\n<li>feink\u00f6rniges Berechtigungsmodell<\/li>\n<li>geplante Jobs<\/li>\n<\/ul>\n<p>Sie k\u00f6nnen mehrere Organisationen definieren, jede davon mit eigenen Projekten und Repositorys.<\/p>\n<p>Jobs k\u00f6nnen manuell oder automatisch durch andere Jobs oder durch User-Commits ausgel\u00f6st werden. Jeder Job f\u00fchrt eine Pipeline mit mehreren Phasen aus. Jede Phase kann ihr eigenes Docker-Image haben, das auf dem neuesten Code, der aus dem angegebenen Zweig extrahiert wurde, ausgef\u00fchrt werden kann.<\/p>\n<p>Es gibt vordefinierte Environment-Variablen, auf die der Benutzer innerhalb der Jobs zugreifen kann, wie z.B. Branch-Name und Commit-Message, die w\u00e4hrend des Builds sehr hilfreich sind. Es gibt auch benutzerdefinierte Variablen, die sensible Werte speichern k\u00f6nnen und die gesch\u00fctzt werden k\u00f6nnen. Nur gesch\u00fctzte Zweige haben Zugriff auf gesch\u00fctzte Variablen.<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtosetuptherunnersandcaching\">So geht&#8217;s: einrichten der Runner und Caching<\/h2>\n<p>Jeder Job wird von einem bestimmten GitLab-Runner ausgef\u00fchrt. Die Runner sind Container-Images, die auf den vom Benutzer zur Verf\u00fcgung gestellten Maschinen ausgef\u00fchrt werden. Sie nehmen Jobs an und f\u00fchren sie aus. Sie k\u00f6nnen so viele Runner definieren, wie Sie m\u00f6chten. Es gibt auch gemeinsam genutzte Runner, die kostenlos zur Verf\u00fcgung gestellt werden, aber Sie m\u00fcssen auf die Builds anderer Benutzer warten.<\/p>\n<p>Wir verwenden keine gemeinsamen Runner. Sie sind jedoch in GitLab im Bereich der CI\/CD-Einstellungen des Projekts zu finden.[\/et_pb_text][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-04-How-to-set-up-the-runners-and-caching.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 04 How to set up the runners and caching&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 04 How to set up the runners and caching&#8220; _builder_version=&#8220;4.4.6&#8243; max_width=&#8220;60vw&#8220; custom_padding=&#8220;2vh||2vh|2vw|false|false&#8220;][\/et_pb_image][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Jeder Runner muss registriert und mit bestimmten Etiketten oder Tags konfiguriert werden. F\u00fcr jedes Projekt k\u00f6nnen wir festlegen, welche Runner f\u00fcr die Ausf\u00fchrung der Pipelines zugewiesen werden sollen, basierend auf den Tags der Runner. Sie m\u00fcssen ein Registrierungs-Token von der Seite der GitLab-Gruppe in den CI\/CD-Einstellungen erhalten.<\/p>\n<p>Wir verwenden eine Docker Compose, um die Runner einmalig zu registrieren und zu initialisieren:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">version: '2'\nservices:\n  register-runner-main-01:\n    restart: 'no'\n    image: gitlab\/gitlab-runner:alpine\n    volumes:\n    - \/opt\/docker_conf\/runner-main-01:\/etc\/gitlab-runner\n    command:\n    - register\n    - --non-interactive\n    - --locked=false\n    - --name= Group - prj - MAIN - 01\n    - --executor=docker\n    - --output-limit=409600\n    - --docker-image=alpine:latest\n    - --docker-volumes=\/var\/run\/docker.sock:\/var\/run\/docker.sock\n    - --docker-volumes=\/opt\/docker_data\/runner-main-01-cache:\/opt\/docker_data\/runner-main-01-cache\n    - --tag-list=otcmain\n    - --docker-privileged\n    - --docker-cache-dir=\/opt\/docker_data\/runner-main-01-cache\n    - --cache-type=s3\n    - --cache-s3-server-address=10.6.yyy.xx:9000\n    - --cache-s3-access-key=minioxxxxx\n    - --cache-s3-secret-key=yyyy\n    - --cache-s3-bucket-name=runner-main\n    - --cache-shared\n    - --cache-s3-insecure\n    environment:\n    - CI_SERVER_URL=https:\/\/gitlab.com\/\n    - REGISTRATION_TOKEN=\u2026<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Runner ist ein Docker-Container, der auf einer unserer Cloud-Maschinen ausgef\u00fchrt wird. Das ausgef\u00fchrte Docker-Image stammt aus dem Docker-Repository gitlab\/gitlab-runner:alpine.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">- --docker-image=alpine:latest<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Befehlsabschnitt definiert, welcher Befehl beim Starten des Containers ausgef\u00fchrt wird. Es gibt eine einmalige Ausf\u00fchrung. <\/p>\n<p>Wir haben die Volumes und Mappings f\u00fcr den Cache und f\u00fcr die Konfiguration definiert.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">volumes:\n    - \/opt\/docker_conf\/runner-main-01:\/etc\/gitlab-runner\n&nbsp;\n    - --docker-volumes=\/opt\/docker_data\/runner-main-01-cache:\/opt\/docker_data\/runner-main-01-cache\n    - --docker-cache-dir=\/opt\/docker_data\/runner-main-01-cache<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Das Caching verwendet einen AWS S3-\u00e4hnlichen Objektspeicher, um die Build-Abh\u00e4ngigkeiten zu speichern. Als S3-Provider wird Minio verwendet:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">    - --docker-cache-dir=\/opt\/docker_data\/runner-main-01-cache\n    - --cache-type=s3\n    - --cache-s3-server-address=10.6.yyy.xx:9000\n    - --cache-s3-access-key=minioxxxxx\n    - --cache-s3-secret-key=yyyy\n    - --cache-s3-bucket-name=runner-main\n    - --cache-shared\n    - --cache-s3-insecure<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der MinIO-Container, der f\u00fcr die Zwischenspeicherung verwendet wird, muss im selben Docker-Netzwerk wie der Runner ausgef\u00fchrt werden.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">version: '2'\nservices:\n  minio:\n    image: minio\/minio\n    container_name: minio1\n    restart: unless-stopped\n    volumes:\n    - \/opt\/docker_conf\/minio-etc:\/root\/.minio\n    - \/opt\/docker_data\/minio-data:\/data\n    ports:\n    - \"9000:9000\"\n    environment:\n    - MINIO_ACCESS_KEY=minioak\n    - MINIO_SECRET_KEY=\u2026\n    command: server \/data\nnetworks:\n  default:\n    external:\n      name: prj-bridge-network<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Ein Taglistenflag beschriftet den Runner; es kann verwendet werden, um den Runner mit einem bestimmten Projekt zu kartieren.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">- --tag-list=otcmain<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Nach der Initialisierung k\u00f6nnen wir die Runner mit Docker Compose auf unseren Code-Qualit\u00e4tsmaschinen starten:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">version: '2'\nservices:\n  runner-main-01:\n    restart: unless-stopped\n    image: gitlab\/gitlab-runner:alpine\n    container_name: runner-main-01\n    volumes:\n    - \/opt\/docker_conf\/runner-main-01:\/etc\/gitlab-runner\n    - \/opt\/docker_data\/runner-main-01-cache:\/opt\/docker_data\/runner-main-01-cache\n    - \/var\/run\/docker.sock:\/var\/run\/docker.sock<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<p>Jeder Runner hat seinen eigenen Cache- und Konfigurationsordner, der zuvor bei der Registrierung konfiguriert wurde.<\/p>\n<p>Um die Hauptl\u00e4ufer bei der langen Ausf\u00fchrung der End-to-End-Tests nicht zu blockieren:<\/p>\n<ul>\n<li>m\u00fcssen wir uns auf die gleiche Weise wie oben registrieren und starten;<\/li>\n<li>die Trigger-Runner m\u00fcssen die nicht-blockierende Ausf\u00fchrung der Pipeline aus einer anderen Projekt-Pipeline starten.<\/li>\n<\/ul>\n<p>Das Startup-Skript sieht genauso aus wie oben:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">services:\n  runner-guitrigger-01:\n    restart: unless-stopped\n    image: gitlab\/gitlab-runner:alpine\n    container_name: runner-guitrigger-01\n    volumes:\n    - \/opt\/docker_conf\/runner-guitrigger-01:\/etc\/gitlab-runner\n    - \/opt\/docker_data\/runner-guitrigger-01-cache:\/opt\/docker_data\/runner-guitrigger-01-cache\n    - \/var\/run\/docker.sock:\/var\/run\/docker.sock<\/pre>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtosetupthepipeline\">So geht&#8217;s: einrichten der Pipeline<\/h2>\n<p>Jedes Projekt lebt in seinem eigenen Git-Repository. Im Projektstammordner befindet sich eine Datei mit dem Namen .gitlab-ci.yml, die die Pipeline f\u00fcr jedes Projekt konfiguriert. Die Datei definiert Variablen, Cache-Einstellungen, auszuf\u00fchrende Vorher- und Nachher-Skripte und die Phasen der Pipeline. Die Phasen sind im Grunde die Schritte, die w\u00e4hrend der Pipeline ausgef\u00fchrt werden sollen, und die Bedingungen f\u00fcr die Ausf\u00fchrung, die ausgel\u00f6st werden sollen. Der letzte Schritt in unserer Pipeline ist die End-to-End-Testphase.[\/et_pb_text][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-05-How-to-set-up-the-pipeline.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 05 How to set up the pipeline&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 05 How to set up the pipeline&#8220; _builder_version=&#8220;4.4.6&#8243; max_width=&#8220;60vw&#8220; custom_padding=&#8220;2vh||2vh|2vw|false|false&#8220;][\/et_pb_image][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wir haben f\u00fcnf Umgebungen, jede mit ihrem spezifischen gesch\u00fctzten Zweig. Wenn dort ein bestimmter Commit durchgef\u00fchrt wird, wird die Anwendung auf dieser speziellen Umgebung gebaut und bereitgestellt. F\u00fcr die Produktionsumgebung m\u00fcssen wir ein bestimmtes Tag mit einer spezifischen Namenskonvention f\u00fcr die Bereitstellung erstellen.<\/p>\n<p>Sie k\u00f6nnen Variablen definieren, die in derselben Datei oder in allen Pipeline-Skripten verwendet werden k\u00f6nnen:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">variables:\nGRADLE_OPTS: \"-Dorg.gradle.daemon=false\"\nDOCKER_DRIVER: overlay2<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Phasen sind wie folgt definiert: [\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">stages:\n  - opssetupchmodfix\n  - test<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<p>Hier haben wir zwei Phasen. Nicht alle Phasen werden in einem einzigen Durchlauf ausgef\u00fchrt. Wir werden sp\u00e4ter jede Phasendefinition detailliert beschreiben.<\/p>\n<p>Um die Ausf\u00fchrungszeit der Jobs zu beschleunigen, m\u00fcssen wir die Abh\u00e4ngigkeiten der einzelnen Builds zwischenspeichern, damit sie nicht jedes Mal heruntergeladen werden m\u00fcssen. Der Cache hat einen Schl\u00fcssel, der aus der vordefinierten Git-Umgebungsvariablen CI_COMMIT_REF_SLUG ausgew\u00e4hlt wird, die den Git-Tag oder den Zweignamen enth\u00e4lt, f\u00fcr den das Projekt erstellt wird:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">&lt;pre class=\"text\" style=\"font-family:monospace;\"&gt;cache:<br\/> key: ${CI_COMMIT_REF_SLUG}<br\/> paths:<br\/> - .gradle\/wrapper<br\/> - .gradle\/caches&lt;\/pre&gt;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wir verwenden pro Zweigcache. Alle Abh\u00e4ngigkeiten werden im Projektordner zwischengespeichert, und der Cache kann bei jeder Jobausf\u00fchrung innerhalb des jeweiligen Projekts wiederverwendet werden. Am Ende des Auftrags werden die angegebenen Ordner in ein Archiv cache.zip gezippt und unter dem angegebenen Schl\u00fcssel auf dem Rechner gespeichert, auf dem der GitLab-Runner ausgef\u00fchrt wird.<\/p>\n<p>Wir k\u00f6nnen ein Skript definieren, das vor dem Start der Ausf\u00fchrung der Phasen ausgef\u00fchrt wird:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">before_script:\n  - export GRADLE_USER_HOME=`pwd`\/.gradle<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Testphase mit der Bezeichnung &#8218;guitest&#8216; startet die Ausf\u00fchrung der End-to-End-Tests:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">guitest:\n  image: registry1.projekt.de\/prj-dind-chrome\n  stage: test   \n  script:\n    - .\/ci\/bin\/guitest.sh \"$EXECUTE_TEST_FOR_ENVIRONMENT\" \"$SRC_TRGR_BRANCH\"\n  tags:\n    - guirunner<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Testphase ist mit bestimmten Runnern verbunden, basierend auf dem Tag-Label. Nur die Runner, die das gleiche Tag &#8218;guirunner&#8216; haben, k\u00f6nnen die Ausf\u00fchrung dieser Phase abholen. <\/p>\n<p>Das Bild registry1.projekt.de\/prj-dind-chrome ist ein benutzerdefiniertes Docker-Image, das auf selenium\/standalone-chrome:latest basiert und mit bash, curl, openssl, git, x11 server, jdk und anderen Tools erweitert wurde, um den End-to-End-Test in einer Browser-Umgebung durchf\u00fchren zu k\u00f6nnen. <\/p>\n<p>Auszug aus der Dockerfile, die zum Erstellen des Images verwendet wird:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">RUN sudo apt-get -y install bash curl git openssl openssh-client openjdk-8-jdk libxpm4 libxrender1 libgtk2.0-0 libnss3 libgconf-2-4 xvfb gtk2-engines-pixbuf xfonts-cyrillic xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable x11-xserver-utils x11-xkb-utils<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Runner, der diese Phase ausf\u00fchrt, startet den angegebenen Container aus dem definierten Bild; wird den Code des End-to-End-Projekts \u00fcberpr\u00fcfen; und startet (innerhalb des Containers) das im Skriptabschnitt definierte Skript:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">script:\n     .\/ci\/bin\/guitest.sh \"$EXECUTE_TEST_FOR_ENVIRONMENT\" \"$SRC_TRGR_BRANCH\"<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<p>Das Skript wird aus dem ausgecheckten Sourcecode bezogen. Es gibt zwei Umgebungsvariablen, die dem Skript \u00fcbergeben werden und die dem Container vom Aufrufer zur Verf\u00fcgung gestellt werden. Sie werden auf der Grundlage der aktuellen Zweig- oder Tag-Variable berechnet, die von GitLab bereitgestellt wird CI_COMMIT_REF_NAME. Ich werde das Skript sp\u00e4ter erkl\u00e4ren.<\/p>\n<p>Der Prozess, der die Ausf\u00fchrung ausl\u00f6st, kann eine andere Pipeline sein, die den Befehl in einer Phase aufruft:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">trigger -a ${GITLABTRIGGER_APITOKEN} -p ${ GITLABTRIGGER_GUITESTTOKEN} -t ${branch} ${GITLABTRIGGER_GUITESTID} \n-e SRC_TRGR_BRANCH=${CI_COMMIT_REF_NAME} \n-e EXECUTE_TEST_FOR_ENVIRONMENT=${GUITEST_ENVIRONMENT^^} \n-e EXECUTE_TEST_FOR_PIPELINE=${CI_PIPELINE_URL}<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Befehl ist im Docker-Image registry.gitlab.com\/finestructure\/pipeline-trigger verf\u00fcgbar. <\/p>\n<p>Der Abschnitt &#8222;artifacts:&#8220; definiert, welche Dateien nach Beendigung des Auftrags zum Download zur Verf\u00fcgung gestellt werden sollen, was die Quelle dieser Dateien ist und wie lange sie aufbewahrt werden sollen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">artifacts:\n    when: always\n    paths:\n      - target\/*\n      - \/opt\/selenium\/config.json\n    expire_in: 1 week\n<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Phase wird nur f\u00fcr bestimmte Zweige ausgef\u00fchrt, die im Abschnitt &#8218;only:&#8216; definiert sind. Dar\u00fcber hinaus wird die Phase nicht ausgef\u00fchrt, wenn die vom Entwickler gegebene Commit-Nachricht den Text &#8222;opssetup&#8220; enth\u00e4lt, der als regul\u00e4rer Ausdruck ausgedr\u00fcckt wird. Es gibt eine logische &#8218;and&#8216;-Bedingung zwischen den beiden.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">only:\n    - branch_dev1\n    - branch_dev2\n    - branch_preview\n    - master\n    - \/^story-\/\n  except:\n    variables:\n      - $CI_COMMIT_MESSAGE =~ \/^opssetup-*\/\n<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Das Skript guitest.sh kann den End-to-End-Test innerhalb des Runner-Containers oder auf einem anderen dedizierten Remote-Rechner starten. Wir begannen mit dem ersten Ansatz, endeten aber damit, die Tests auf einer dedizierten Maschine laufen zu lassen. <\/p>\n<p>Der erste Ansatz verwendet die Befehle:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">Xvfb -ac :99 -screen 0 1280x1024x16 &amp;\nexport DISPLAY=:99\n\n.\/gradlew -i clean runAParallelSuite aggregate -P webdriver.base.url=$TARGET_BASE_URL\n<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der erste Schritt bestand darin, den In-Memory-Display-Server und die Aufl\u00f6sung einzurichten. Im zweiten Schritt starten wir einen benutzerdefinierten Gradle-Task. Weitere Details folgen.<\/p>\n<p>Dieser Ansatz l\u00e4sst sich nicht sehr gut skalieren. Wir bekamen h\u00e4ufige Speicherprobleme, so dass wir beschlossen, die Tests auf einem dedizierten Computer mit den Befehlen zu starten:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">openssl enc -aes-XXalgo -d -pass env:GRP_SSL_ENCSECRET -in ci\/secrets-enc\/id_rsa-usr-dockerexec.dat &gt;| ci\/secrets\/id_rsa-usr-dockerexec\n\nssh -i ci\/secrets\/id_rsa-usr-dockerex usr-dockerex@10.6.xx.xx  -o StrictHostKeyChecking=no \"\/opt\/docker_exec\/launch-tests.sh ${CI_JOB_ID} ${TARGET_LABEL} ${TARGET_BRANCH} ${TARGET_ENV}\"\n<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<p>Mit Hilfe von Ansible haben wir den Rechner mit den richtigen Benutzerkonten und Berechtigungen eingerichtet, um die GUI-Tests von einem Remote-Rechner aus starten zu k\u00f6nnen. Der geheime Benutzerschl\u00fcssel wird bereitgestellt, nachdem er mithilfe einer gesch\u00fctzten Umgebungsvariablen entschl\u00fcsselt GRP_SSL_ENCSECRET, die in der GitLab-Benutzeroberfl\u00e4che definiert ist. Die Skriptvariablen wurden auf der Grundlage des Zweignamens und der Standardvariablen von GitLab berechnet.<br \/> Jedem Job wird eine eindeutige ID zugewiesen, die als CI_JOB_ID angezeigt wird. Das TARGET_LABEL wird verwendet, um die Docker-Image-Labels anzugeben, die bei der Ausf\u00fchrung des Tests verwendet werden sollen. Die beiden anderen Variablen geben den Zweig an, von dem aus der Testcode und die Umgebung beim Herunterladen der Bilder zu ber\u00fccksichtigen sind. In einem weiteren Abschnitt erkl\u00e4ren wir das Startskript.<\/p>\n<p>Eine weitere Phase namens &#8222;opssetupchmodfix&#8220; wird nur ausgef\u00fchrt, wenn die bereitgestellte Commit-Nachricht den Text &#8222;opssetup-chmod-fix&#8220; enth\u00e4lt, und nur auf dem mit &#8222;otcprj&#8220; gekennzeichneten Runner. Die Phase \u00e4ndert die Berechtigungen der ausf\u00fchrbaren Bash-Dateien, die von git ausgecheckt wurden, in den aktuellen Projektarbeitsbereichsordner und \u00fcbertr\u00e4gt die \u00c4nderungen zur\u00fcck an git. Die Standardberechtigungen verweigern die Ausf\u00fchrung.<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">opssetup-chmod-fix:\n  stage: opssetupchmodfix\n  image: registry1.projekt.de\/prj-dind-base\n  script:\n    - chmod oga+x .\/ci\/bin\/*.sh\n    - .\/ci\/bin\/fixexecuteflag.sh\n  tags:\n    - otcprj\n  only:\n    variables:\n      - $CI_COMMIT_MESSAGE =~ \/^opssetup-chmod-fix*\/\n<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Phase muss einmal ausgef\u00fchrt werden, wenn sie aus einer Windows-Umgebung kommt, da es keine einfache M\u00f6glichkeit gibt, die Ausf\u00fchrungsberechtigung f\u00fcr die Bash-Dateien zu setzen.[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtoisolatethetests\">So geht&#8217;s: isolieren die Tests<\/h2>\n<p>Man k\u00f6nnte meinen, dass die Isolierung der Tests eine schlechte Sache ist, weil man kein Feedback vom echten System, den Daten und den Benutzern bekommt. In den meisten F\u00e4llen besteht der Zweck der End-to-End-Tests jedoch darin, zu \u00fcberpr\u00fcfen, ob die vorhandene gesch\u00e4ftskritische Funktionalit\u00e4t nach der Durchf\u00fchrung von \u00c4nderungen noch wie erwartet funktioniert. Die \u00dcberpr\u00fcfung der Systemkonsistenz oder -leistung darf nicht mithilfe der End-to-End-Tests durchgef\u00fchrt werden.[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtopreparetheenvironmentforrunningthetests\">So geht&#8217;s: vorbereiten der Umgebung f\u00fcr die Durchf\u00fchrung der Tests<\/h2>\n<p>Wir haben eine Cloud-Maschine f\u00fcr die Ausf\u00fchrung der End-to-End-Tests mithilfe von Terraform-Skripten erstellt. Wenn mehrere Maschinen ben\u00f6tigt werden, k\u00f6nnen diese dynamisch erstellt werden. Die Maschine wird mit Ansible konfiguriert. Der Benutzer &#8222;usr-dockerex&#8220; wird angelegt und darf (A) eine Verbindung \u00fcber seinen ssh-Schl\u00fcssel herstellen und (B) das Startskript f\u00fcr den End-to-End-Test ausf\u00fchren. Das Skript launch-tests.sh wird w\u00e4hrend der Maschineneinrichtung kopiert.<\/p>\n<p>Wir m\u00fcssen in der Lage sein, mehrere End-to-End-Tests f\u00fcr verschiedene Zweige und Umgebungen parallel laufen zu lassen. Daher verwenden wir die Job-ID, um alle von einem Lauf gestarteten Dienste voranzustellen. Wir verwenden Docker Compose, um die Container zu starten.<\/p>\n<p>An jeden Containernamen f\u00fcgen wir die Auftrags-ID wie folgt an:<\/p>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">container_name: ui-client${JOB_ID}<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wir erstellen ein Docker-Image in der Pipeline jedes Microservices und schieben es in unser Docker-Repository. Von dort aus werden die End-to-End-Tests die Bilder ziehen und starten. Verschiedene Zweige erzeugen verschiedene Docker-Images, mit wohldefinierten Bezeichnungen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">image: \"registry1.projekt.de\/ui-client:${ CLIENT_IMAGE_TAG}\"<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Das Tag wird mithilfe der GIT-API basierend auf dem Quellzweig, der Zielumgebung und dem Projekt berechnet, das den Build ausgel\u00f6st hat. Bei der Arbeit an einem Feature k\u00f6nnen mehrere Microservices und UI-Clients betroffen sein. <\/p>\n<p>Die Microservices, die nicht ge\u00e4ndert werden, m\u00fcssen f\u00fcr den End-to-End-Test ebenfalls gestartet werden. Dazu m\u00fcssen wir eine Zielumgebung angeben, von der wir die neuesten Images f\u00fcr diese Umgebung erhalten. Jede Umgebung ist an einen gesch\u00fctzten Zweig gebunden. <\/p>\n<p>Nehmen wir an, wir haben 3 Microservices und nur 2 werden ge\u00e4ndert. Jeder befindet sich in seinem eigenen Git-Repository. Die \u00c4nderungen f\u00fcr dieselbe Story\/dasselbe Feature werden in einem Zweig mit demselben Namen durchgef\u00fchrt, sagen wir feature1. Die erste Umgebung, in der das Feature bereitgestellt wird, sollte die Entwicklungsumgebung sein. Daher muss der unver\u00e4nderte microservice3 das neueste Image verwenden, das f\u00fcr die Entwicklungsumgebung erstellt wurde. Die verwendeten Bilder sind in diesem Fall die folgenden:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">\u2022\timage: \"registry1.projekt.de\/microservice1:feature1\" \n\u2022\timage: \"registry1.projekt.de\/ microservice2:feature1\" \n\u2022\timage: \"registry1.projekt.de\/ microservice3:dev1_latest\"<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wenn der Zweig feature1 f\u00fcr den Microservice3 existieren w\u00fcrde, w\u00fcrde er auch f\u00fcr die End-to-End-Tests verwendet werden. Wir pr\u00fcfen die Existenz eines Zweigs mit dem folgenden Skript:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">function check_branch_existence(){\n     local result=$1\n    local project=$2\n    local branch=$3\n    local exists=$(curl -I -so \/dev\/null -w \"%{http_code}\" \"https:\/\/gitlab.com\/api\/v4\/projects\/${project}\/repository\/branches\/${branch}?private_token=${GRP_GITUSER_ACCESSTOKEN}\")\n    eval $result=\"'$exists'\"\n}\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wenn die Verzweigung existiert, sollte die Ausgabeergebnisvariable den 204 HTTP-Antwortcode enthalten.<\/p>\n<p>Wir m\u00fcssen die Existenz eines Docker-Image-Tags \u00fcberpr\u00fcfen, um den richtigen Container zu starten oder auf ein Standard-Image zur\u00fcckzugreifen, das eigentlich das Dev-Image ist. Wir verwenden die folgende Funktion:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">function check_image_tag_existence(){\n    local result=$1\n    local project=$2\n    local image_tag=$3\n    local repo=$4\n    echo \"docker inspect --type=image ${repo}\/${project}:${image_tag}\"\n    local exists=$(docker inspect --type=image \"${repo}\/${project}:${image_tag}\" --format \"{{.Id}}\" &gt; \/dev\/null 2&gt;&amp;1 &amp;&amp; echo $? || echo $?) \n    echo \"Exists image? ${exists}\"\n    if [ $exists -eq 1 ]; then\n\techo \"try to pull image\"\n\tlocal pullresult=$(docker pull \"${repo}\/${project}:${image_tag}\";echo $?)\n\techo \"pull result ${pullresult}\"\n\techo \"tried to pull image ${repo}\/${project}:${image_tag}\"\n    fi\n    exists=$(docker inspect --type=image \"${repo}\/${project}:${image_tag}\" --format \"{{.Id}}\" &gt; \/dev\/null 2&gt;&amp;1 &amp;&amp; echo $? || echo $?) \n    echo \"after second inspect $exists\"\n    eval $result=\"'$exists'\"\n}<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wenn das Image nicht lokal heruntergeladen wird, findet der Befehl &#8222;docker inspect&#8220; es nicht. Daher wird vor dem zweiten inspect-Befehl ein Pull durchgef\u00fchrt. Das Ergebnis der zweiten Inspektion wird zur\u00fcckgegeben.<\/p>\n<p>Wir iterieren durch alle unsere GitLab-Microservices-Projekte, um die richtigen Umgebungsvariablen mit den Container-Images und Tags zu berechnen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">projects=(\"1233xxx\" \"1224xxxx\"\u2026 )\nproject_names=(..)\nproject_vars=(..)\nfor i in ${!projects[@]};\n\tdo\ncheckImageTag ${projects[$i]} ${project_names[$i]} ${project_vars[$i]} $imageTag \"dockerregistry1.server\" \"dev1-latest\"\n\tdone\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Funktion checkImageTag exportiert f\u00fcr jeden Microservice die richtigen Umgebungsvariablen, bzw. gibt sie vor.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">function checkImageTag(){\n\t    local curProjId=$1\n\t\tlocal curProjName=$2\n\t\tlocal curProjVar=$3\n\t\tlocal curProjTag=$4\n\t\tlocal curRegistry=$5\n\t\tlocal envBranch=$6\n\t\tcheck_image_tag_existence imageexistresult $curProjName $curProjTag $curRegistry\n\t\tif [ $imageexistresult -eq 0 ]; then \n\t\t\teval \"export $(echo ${curProjVar}_IMAGE_TAG | tr [a-z] [A-Z])=$imageTag\"\n\t\telse\n\t\t\t#fallback to the default tag\n\t\t\tcheck_image_tag_existence imageexistresult $curProjName $envBranch $curRegistry\n&nbsp;\n\t\t\tif [ $imageexistresult -eq 0 ]; then \n\t\t\t\teval \"export $(echo ${curProjVar}_IMAGE_TAG | tr [a-z] [A-Z])=dev1-latest\"\n\t\t\telse\n\t\t\t\techo \"image ${curProjTag} for project ${curProjName} does not exist!\"\n\t\t\t\texit 1\n\t\t\tfi\n\t\tfi\n}<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wir werden f\u00fcr jeden Microservice eine Variable in Form von SERVICE_VAR_NAME_IMAGE_TAG exportiert haben. Der Var-Name ist nach Konvention der Gro\u00dfbuchstabe des Dienstnamens, wobei das Minuszeichen durch einen Unterstrich ersetzt wird.<\/p>\n<p>Bisher haben wir (A) die Containernamen so berechnet, dass sie f\u00fcr verschiedene Jobs eindeutig sind, und (B) die richtigen Docker-Image-Tags basierend auf dem Zweignamen und der Zielumgebung. Wir vermissen noch die richtige Bereinigung, bevor wir die neuen Container f\u00fcr die Tests starten.<\/p>\n<p>Die Ausf\u00fchrung der End-to-End-Tests dauert weniger als eine Stunde, so dass wir alle Container, die vor mehr als einer Stunde gestartet wurden und noch laufen, stoppen k\u00f6nnen. Die Container haben das Pr\u00e4fix ad. Wir filtern diese Container und z\u00e4hlen sie. Wenn es solche Container gibt, verwenden wir Docker Stop und geben die Liste der gefilterten Container-IDs aus.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">if [ `docker ps --filter \"status=running\" --filter \"name=ad\" | grep 'hour.* ago' | awk '{print $1}' | wc -l ` -gt 0 ] ; then\ndocker stop $(docker ps --filter \"status=running\" --filter \"name=ad\" | grep 'hour.* ago' | awk '{print $1}')\nfi<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wir werden die Container danach l\u00f6schen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">if [ `docker ps --filter \"status=exited\" | grep 'hour.* ago' | awk '{print $1}' | wc -l ` -gt 0 ] ; then\ndocker rm $(docker ps --filter \"status=exited\" | grep 'hour.* ago' | awk '{print $1}')\nfi<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Abh\u00e4ngig von den Ressourcen der Testmaschine(n) k\u00f6nnen wir die Anzahl der Tests begrenzen, die parallel auf einer Maschine laufen. Es spielt keine Rolle, welcher Dienst gez\u00e4hlt wird, es kann jeder sein.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">if [ `docker inspect --format='{{.Name}} ' $(docker ps -aq --filter \"status=running\" --filter \"name=admicroservice1*\" )  | cut -d r -f 3 | wc -l` -lt 5 ] ; then\n echo 'allowing not more than 5 running gui tests'\nelse\n echo 'there are running in parallel already 5 gui test, please retry later '\n exit 1\nfi<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]F\u00fcr jede Job-ID wird ein neues Netzwerk erstellt.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">export NETWORK_BRIDGE=nwkbguitest${JOB_ID}\n[ ! \"$(docker network ls | grep $NETWORK_BRIDGE)\" ] &amp;&amp; docker network create -d bridge $NETWORK_BRIDGE || echo \"Network present!\"\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wenn die Container bereits f\u00fcr dieselbe Auftrags-ID laufen, stoppen und entfernen wir sie \u00fcber die folgenden Befehle:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">vardockers=`docker ps -a --filter \"name=*${JOB_ID}\"| wc -l`\nif [ $vardockers -eq 1 ]\nthen\n echo \"no containers\"\nelse\n        echo \"stop and remove all containers\"\n        docker stop $(docker ps -a -q --filter \"name=*${JOB_ID}\")\n        docker rm $(docker ps -a -q --filter \"name=*${JOB_ID}\")\nfi<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Nachdem die erste Bereinigung durchgef\u00fchrt wurde, starten wir alle Container mit Docker Compose im Hintergrund.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">docker-compose -f \/opt\/docker_compose\/docker-compose-apps.yml up -d<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Anschlie\u00dfend werden die IPs der Container auf der Konsole protokolliert und die Log-Ausgabe des End-to-End-Testcontainers wird auf die Konsole umgeleitet.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">docker inspect --format='{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -q)\ndocker logs -f endtoend-tests${JOB_ID}<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Wenn die Tests abgeschlossen sind, wird die endg\u00fcltige Bereinigung durchgef\u00fchrt und der Ergebniscode wird ausgewertet und zur\u00fcckgegeben.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">result=`docker inspect $(docker ps -aq --filter \"name=endtoend-tests${JOB_ID}\") --format='{{.State.ExitCode}}'`\ndocker-compose -f \/opt\/docker_compose\/docker-compose-apps.yml down\ndocker network rm $NETWORK_BRIDGE\ndocker network prune -f\ndocker image prune -f\ndocker volume prune -f\nexit $result<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Docker Compose .yml-Datei wird in einem weiteren Abschnitt erl\u00e4utert.[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtopreparethedataforthetests\">So geht&#8217;s: bereiten die Daten f\u00fcr die Tests<\/h2>\n<p>Wir verwenden das Spock-Framework f\u00fcr Systemtests unserer Rest-API. Spock ist eine Test- und Spezifikationsplattform f\u00fcr Java- und Groovy-Anwendungen, die \u00fcber den Junit-Runner einfach in IDEs und CI-Pipelines integriert werden kann. Mit Spock k\u00f6nnen wir Spezifikationen schreiben, die die erwarteten Funktionen eines zu testenden Systems beschreiben. Die Tests k\u00f6nnen eine Dokumentation f\u00fcr ein breiteres Publikum als die Entwickler erzeugen, indem sie die beschrifteten Bl\u00f6cke &#8222;given&#8220;, &#8222;when&#8220; und &#8222;then&#8220; verwenden (wie im Folgenden):[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220; locked=&#8220;off&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">given: \"an admin user\"\n\/\/ ...code\nwhen: \"his company settings are changed\"\n\/\/ ...code\nthen: \"the user is notified\"\n\/\/...code<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243; locked=&#8220;off&#8220;]Die erstellten Berichte sehen wie folgt aus:[\/et_pb_text][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-06-Reports.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 06 Reports&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 06 Reports&#8220; _builder_version=&#8220;4.4.6&#8243; max_width=&#8220;60vw&#8220; custom_padding=&#8220;2vh||2vh|2vw|false|false&#8220; locked=&#8220;off&#8220;][\/et_pb_image][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243; locked=&#8220;off&#8220;]Die Tests sind in Testsuiten und Specs organisiert. Jede Spec befasst sich mit einem bestimmten Bereich unserer APIs.[\/et_pb_text][et_pb_image src=&#8220;\/\/cdn.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-07-Reports-scaled.jpg&#8220; alt=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 07 Reports&#8220; title_text=&#8220;Berg Software &#8211; End-to-end tests an GitLab integration &#8211; 07 Reports&#8220; _builder_version=&#8220;4.4.6&#8243; max_width=&#8220;60vw&#8220; custom_padding=&#8220;2vh||2vh|2vw|false|false&#8220; locked=&#8220;off&#8220;][\/et_pb_image][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243; locked=&#8220;off&#8220;]Grunds\u00e4tzlich verwenden wir die Systemtests, um eine leere Datenbank zu f\u00fcllen, auf der wir die End-to-End-Tests ausf\u00fchren. Eine kleine Anzahl von Systemtests wird speziell f\u00fcr den End-to-End-Test geschrieben. Dies ist eine Notwendigkeit, bei der einige Daten ben\u00f6tigt werden, oder einige Workflows m\u00fcssen im Voraus vorbereitet werden, da dies nicht nur von den End-to-End-Tests erstellt werden kann. Die Tests, die zur Erleichterung der Durchf\u00fchrung von End-to-End-Tests erstellt werden, sollten klar unterschieden werden.<\/p>\n<p>F\u00fcr Tests werden bestimmte Benutzer verwendet, um (so weit wie m\u00f6glich) die Interferenzen mit den vorhandenen Benutzern zu isolieren, die auf dem System aktiv sind. <\/p>\n<p>Zu Beginn der Ausf\u00fchrung werden die Testdaten vorbereitet. Am Ende wird die Bereinigung durchgef\u00fchrt.<\/p>\n<p>Die Docker Compose-Datei von oben enth\u00e4lt den MySQL-Dienst, der beim Starten ein SQL-Skript ausf\u00fchrt, um die leeren Datenbanken zu erstellen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">db-mysql:\n        container_name: prj-mysql${JOB_ID}\n        image: mysql:5.8\n        volumes:\n            - \".\/setmode.cnf:\/etc\/mysql\/conf.d\/setmode.cnf\"\n        ports:\n            - \"3306\"\n        entrypoint:\n             sh -c \"\n               echo 'CREATE DATABASE IF NOT EXISTS at_projects  \/*!40100 DEFAULT CHARACTER SET utf8 *\/; CREATE DATABASE IF NOT EXISTS at_server; \u2026' &gt; \/docker-entrypoint-initdb.d\/init.sql;\n               \/usr\/local\/bin\/docker-entrypoint.sh --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci\n             \"<\/pre>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtorunthetestswithdockercompose\">So geht&#8217;s: ausf\u00fchren der Tests mit Docker Compose<\/h2>\n<p>Alle Microservices und erforderlichen Laufzeitabh\u00e4ngigkeiten werden in der Docker Compose-Datei deklariert. Die Containernamen sind eindeutig, w\u00e4hrend die Image-Tags aus dem Startskript berechnet und als Umgebungsvariablen bereitgestellt werden.<\/p>\n<p>Alle Dienste f\u00fcr einen Auftrag werden im gleichen Netzwerk gestartet, einschlie\u00dflich des Datenbankservers.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">networks:\n  default:\n    external:\n      name: ${NETWORK_BRIDGE}<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]F\u00fcr jeden Container m\u00fcssen einige Ressourcenlimits festgelegt werden (z. B. Speicher und CPU).<\/p>\n<p>Ein typischer Backend-Dienst sieht wie folgt aus:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">services: \n prj-server:\n    image: \"registry1\/prj-server:${PRJ_SERVER_IMAGE_TAG}\"\n    container_name: prj-server${JOB_ID}\n    environment:\n      - \"SPRING_PROFILES_ACTIVE=otcdev,swagger\"\n      - \"SQL_SERVER_IP=db-mysql${ JOB_ID}\"\n\u2026\n    ports:\n      - 8080\n    restart: always\n    mem_limit: 2500m\n    depends_on:\n        - db-mysql<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Ein typischer Frontend-Dienst sieht wie folgt aus:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">ui-client:\n    image: \"registry1 \/ui-client:${UI_CLIENT_IMAGE_TAG}\"\n    container_name: ui-client${JOB_ID}\n    environment:\n      - \"BACKEND_SERVER_URL=http:\/\/prj-server${ JOB_ID}:8080\"\n      - \"BACKEND_CHECKLIST_URL=http:\/\/prj-checklists${JOB_ID}:8084\"\n    ports:\n      - 8085\n    restart: always\n    command: \/bin\/bash -c \"envsubst &lt; \/opt\/enviroment-endpoints.template &gt; \/opt\/enviroment-endpoints.json &amp;&amp; cp \/opt\/enviroment-endpoints.json \/usr\/share\/nginx\/html\/assets\/enviroment-endpoints.json &amp;&amp; exec nginx -g 'daemon off;'\"<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Eine interessante Sache ist die Ersetzung der Umgebungsvariablen der Backend-URLs in eine Datei, die dem nginx-Webserver zur Verf\u00fcgung gestellt wird. Diese Datei wird dann in das UI-Image eingebunden, um das UI der End-to-End-Tests auf das richtige Backend zu verweisen. An diesem Punkt ben\u00f6tigen wir nur eine Instanz f\u00fcr jeden Dienst. <\/p>\n<p>Das Ausf\u00fchren des Tests wird tats\u00e4chlich in einem speziellen Container ausgef\u00fchrt, der von einem Chrombild aus gestartet wurde. Das Bild mit allen eingestellten Abh\u00e4ngigkeiten ist bereit, den End-to-End-Test auszuf\u00fchren.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">services:\n endtoend-tests:\n    image: registry1.projekt-adis.de\/adis-dind-chrome\n    container_name: endtoend-tests${JOB_ID}\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Abschnitt ordnet einen Host-Ordner einem Container-Ordner zu. Der Host-Ordner bleibt auch nach Beendigung der Arbeit des Containers bestehen. Hier werden die End-to-End-Testberichte gespeichert.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">volumes:\n      - \/opt\/docker_data\/guitest:\/repo\/tests<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Einstiegspunkt definiert den Befehl, der beim Starten des Containers ausgef\u00fchrt werden soll. Es gibt mehrere Linux-Befehle, die durch ;[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">entrypoint: &gt;\t\t\t\t\t           \n        \/bin\/sh -c \"<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Zun\u00e4chst wird der Git-Benutzer so konfiguriert, dass er beim \u00dcbertragen erscheint.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">git config --global user.name \\\"${GRP_GITUSER_NAME}\\\";\t\ngit config --global user.email \\\"${GRP_GITUSER_EMAIL}\\\";\n <\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Es werden eindeutige Ordner f\u00fcr jede Job-ID erstellt und Zugriffsrechte vergeben.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">sudo mkdir repo;\nsudo chmod a+rwx repo;\ncd repo;\nsudo mkdir tests\/${JOB_ID};\nsudo chmod a+rwx tests\/${JOB_ID};\nsudo rm -rf adis-systemtest;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der Code f\u00fcr den Systemtest wird ausgecheckt und in der frischen Umgebung ausgef\u00fchrt, um die End-to-End-Testdaten zu f\u00fcllen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">git -C . clone --branch ${PRJ_SYSTEMTEST_BRANCH} https:\/\/${GRP_GITUSER_LOGON}:${GRP_GITUSER_ACCESSTOKEN}@gitlab.com\/company\/projects\/cust\/prj\/prj-systemtest.git;\n        chmod oga+x .\/prj-systemtest\/ci\/bin\/systemtest.sh;\n        cd prj-systemtest;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Tests zum Auff\u00fcllen der Daten werden gestartet, wobei sie die richtigen Backend-URLs erhalten.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">.\/ci\/bin\/systemtest.sh ISOLATED http:\/\/prj-server${JOB_ID}:8080 http:\/\/prj-projects${ JOB_ID}:8081 http:\/\/prj-checklists${ JOB_ID }:8084;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Testergebnisse werden geparst, und der Auftrag ist fehlgeschlagen, wenn es Fehler gibt.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">cp -R build\/test-results\/test \/repo\/tests\/${ JOB_ID}\/test-results-system;\ncat \/repo\/tests\/${ JOB_ID}\/test-results-system\/TEST-specs.TestSuite.xml;\ncat \/repo\/tests\/${JOB_ID}\/test-results-system\/*.xml &gt;&gt; \/repo\/tests\/${ JOB_ID}\/test-results-system\/systestresult.log;\n[ `cat \/repo\/tests\/${JOB_ID}\/test-results-system\/systestresult.log | grep '\\failures=.[^0].' | wc -l` -eq 0 ] &amp;&amp; echo 'system test success' || exit 1;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die End-to-End-Tests werden aus Git ausgecheckt (d. h. aus dem berechneten Zweig).[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">cd ..;\nsudo rm -rf prj-guitest;\ngit -C . clone --branch ${PRJ_GUITEST_BRANCH} https:\/\/${GRP_GITUSER_LOGON}:${GRP_GITUSER_ACCESSTOKEN}@gitlab.com\/company\/projects\/client\/prj\/prj-guitest.git;\nchmod oga+x .\/prj-guitest\/ci\/bin\/*.sh;\ncd prj-guitest;\n <\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Der End-to-End-Test wird gestartet, wobei auch die URLs der Clients der Benutzeroberfl\u00e4che bereitgestellt werden.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">.\/ci\/bin\/guitest.sh ISOLATED http:\/\/prj-client${ JOB_ID} http:\/\/prj-admin-client${ JOB_ID};<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Die Ergebnisse werden ausgewertet, geparst und an einen Ort kopiert, an dem der nginx-Server sie nach au\u00dfen liefern kann.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">cp -R target\/site \/repo\/tests\/${ JOB_ID}\/test-site;\n        cp -R build\/test-results\/runAParallelSuite \/repo\/tests\/${ JOB_ID }\/test-results;\n        cp -R build\/reports\/tests\/runAParallelSuite \/repo\/tests\/${ JOB_ID }\/test-reports;\n        cat \/repo\/tests\/${ JOB_ID }\/test-site\/serenity\/results.csv;\n        [ `tail -n +2 \/repo\/tests\/${ JOB_ID }\/test-site\/serenity\/results.csv | grep -v SUCCESS | wc -l` -eq 0 ] &amp;&amp; echo 'gui test successful' || exit 1;\n        \"\n    mem_limit: 7500m<\/pre>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtocleanupafterthetests\">So geht&#8217;s: aufr\u00e4umen nach den Tests<\/h2>\n<p>Nach der Ausf\u00fchrung der Testsuiten f\u00fchren wir den Bereinigungsschritt aus. Die Bereinigung kann aus verschiedenen Gr\u00fcnden fehlschlagen, z. B. abrupter Programmabbruch aufgrund fehlender Ressourcen, besch\u00e4digte Daten oder Netzwerkfehler, fehlerhafte Bereinigungsprozedur oder eine laufende Neuverteilung. Eine M\u00f6glichkeit, mit dieser Situation umzugehen, besteht darin, die Bereinigung auch zu Beginn des Tests durchzuf\u00fchren. Wenn die Bereinigung nicht erfolgreich ist, dann schlagen Sie den Test fehl. Manchmal k\u00f6nnen Sie keine erstellten Ressourcen l\u00f6schen, wenn die L\u00f6sch-API nicht verf\u00fcgbar ist oder die Bereinigung zu teuer ist. <\/p>\n<p>Unsere L\u00f6sung besteht darin, f\u00fcr jede End-to-End-Testausf\u00fchrung immer eine saubere Datenbank zu verwenden und diese mit den Systemtests zu best\u00fccken. Dazu ben\u00f6tigten wir eine isolierte Umgebung.[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtomakethetestsasfastaspossible\">So geht&#8217;s: die Tests so schnell wie m\u00f6glich zu machen<\/h2>\n<p>Die End-to-End-Tests werden parallel ausgef\u00fchrt, um die Ausf\u00fchrungszeit zu minimieren. Dazu werden die Tests in unabh\u00e4ngige Testsuiten aufgeteilt. Das bedeutet, dass die von einer Suite verbrauchten oder produzierten Daten die Daten anderer parallel laufender Suiten nicht ver\u00e4ndern. Achten Sie darauf, wenn sich die Aktionen bestimmter Benutzer auf die laufenden Sitzungen aller anderen Benutzer auswirken. Zum Beispiel: die Benutzersprache wird ge\u00e4ndert, die Benutzereinstellung, das Men\u00fc nicht anzuzeigen, wird ge\u00e4ndert, die Berechtigungen werden ge\u00e4ndert.<\/p>\n<p>Wie oben gesehen, gibt es einen Gradle-Task, der den Standard-Test-Task erweitert, dem wir die Anwendungs-URLs \u00fcbergeben, auf die der Browser zeigen soll: <\/p>\n<p>F\u00fcr die Standard-Testaufgabe (d. h. diejenige, auf die der Browser basierend auf den URLs der Anwendung zeigen soll) gibt es eine Gradle-Aufgabe, die diese erweitert.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">task runAParallelSuite(type: Test) {\n    systemProperty \"webdriver.base.url\", findProperty(\"webdriver.base.url\")\n    maxParallelForks = 3\n    forkEvery = 1\n    include '**\/**TestSuite.class'\n    testLogging.showStandardStreams = true\n}\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Es gibt 3 Testsuiten, die parallel auf drei Threads ausgef\u00fchrt werden. <\/p>\n<p>Weitere Faktoren, die die Leistung beeinflussen, sind die Logging-Funktion und die Erfassung von Screenshots. Wir haben die Logging-Funktion auf ein akzeptables Niveau reduziert und die Screenshots so eingestellt, dass sie nur im Fehlerfall aufgenommen werden. Die Datei serenity.properties, die sich im Stammverzeichnis des End-to-End-Projekts befindet, enth\u00e4lt die folgenden Konfigurationen:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">serenity.take.screenshots=FOR_FAILURES\nserenity.logging=NORMAL<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Um die Browserfenster nicht zu st\u00f6ren, ist auch das Laufen im Headless-Modus eine Voraussetzung. Unter Linux muss ein virtuelles Terminal mit einer bestimmten Aufl\u00f6sung eingerichtet werden, wie oben gezeigt.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">chrome.switches=--headless --disable-extensions --disable-gpu --disable-dev-shm-usage --no-sandbox<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Irgendwann bekamen wir eine Menge ung\u00fcltiger Sitzungsfehler und den Headless-Modus, die durch Hinzuf\u00fcgen der beiden Flags -disable-gpu -disable-dev-shm-usage behoben wurden.<\/p>\n<p>Innerhalb der Ende-zu-Ende-Tests m\u00fcssen f\u00fcr maximale Performance xpaths auf Basis von ids verwendet werden.[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Howtomaintainthetestsuite\">So geht&#8217;s: Wartung der Testsuite<\/h2>\n<p>User Journeys werden f\u00fcr gesch\u00e4ftskritische Szenarien geschrieben. Hier f\u00fchrt der Benutzer verschiedene Aktionen aus, um ein bestimmtes Ziel zu erreichen. Die Aufgaben werden in der Benutzeroberfl\u00e4che ausgef\u00fchrt, indem er mit ihr interagiert. Der Test stellt Fragen oder macht Annahmen \u00fcber das Ergebnis der sichtbaren Aufgabe.<\/p>\n<p>Gruppieren Sie den Code in wiederverwendbare Aufgaben oder Aktionen, die vom Benutzer ausgef\u00fchrt werden:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">public abstract class BaseLoginTask implements Task\npublic class OpenMyProfilePage implements Task\npublic class EnterValueIntoField implements Task\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Schreiben Sie wiederverwendbare Fragen oder Abfragen f\u00fcr die Benutzeroberfl\u00e4che:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">public class ConfirmationMessageAppears implements Question&lt;String&gt;\npublic class ValueInColumnOfTable implements Question&lt;List&lt;String&gt;&gt;\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Um eine wartbare Testsuite zu haben, ist eine wichtige Sache, xpaths zu verwenden, die auf ids basieren und nicht auf parent\/child-Relationen innerhalb des HTML. Die \u00c4nderungen am Layout werden sehr oft durchgef\u00fchrt und sollten die End-to-End-Tests nicht beeinflussen. Verwenden Sie Konstrukte wie dieses:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">public static Target ADD_TASK = Target.the(\"AddTask button\").located(By.id(\"btn-add-tasks\"))<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]statt:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">Target.the(\"The second selected interaction\").locatedBy(\"\/\/div\/span\/app-link-or-text\/a\");<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Eine andere Sache ist, keine hard-codierten Wartezeiten einzuf\u00fchren (wie &#8222;warte f\u00fcr 20 Sekunden&#8220;). Verwenden Sie stattdessen Konstrukte, die auf das Eintreten bestimmter Bedingungen warten und eine Zeit\u00fcberschreitung vorsehen: [\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">WaitUntil.the(ChecklistTemplates.ADD_CHECKLIST_TEMPLATE_BUTTON,             WebElementStateMatchers.isEnabled()) \n.forNoMoreThan(TimeConstants.SECONDS_10). seconds().performAs(actor);\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]Es sollten mehrere Stufen von Timeouts als Konstanten festgelegt werden, die \u00fcberall verwendet werden k\u00f6nnen. Au\u00dferdem sollte ein Faktor zum Anpassen der Timeouts auf einmal festgelegt und als Systemeigenschaften angegeben werden, wenn sie in einer langsameren Umgebung laufen.[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">public static final int SECONDS_1 = 1 * factor;\n    public static final int SECONDS_3 = 3 * factor;\n    public static final int SECONDS_10 = 10 * factor;    \n    public static final int LOADER = 5 * factor; \n    public static final int LONG_LIST = 10 * factor;\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]In serenity.properties haben wir:[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family:monospace;\">#How long webdriver waits for elements to appear by default, in milliseconds.\nwebdriver.wait.for.timeout=5000\n#How long webdriver waits by default when you use a fluent waiting method, in milliseconds.\nwebdriver.timeouts.implicitlywait=5000\n#How long should the driver wait for elements not immediately visible, in milliseconds.\nserenity.timeout=5000\n&nbsp;<\/pre>\n<p>[\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]F\u00fcr langsame Seiten empfehlen wir, wenn m\u00f6glich, die Einf\u00fchrung eines Fortschrittsbalkens oder einer Ladeanzeige in der Benutzeroberfl\u00e4che, die zu Beginn und am Ende langlaufender Vorg\u00e4nge \u00fcberpr\u00fcft werden kann. [\/et_pb_text][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1em&#8220; text_line_height=&#8220;1.3em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;1em&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; background_color=&#8220;#f8f8f8&#8243; custom_margin=&#8220;|5vw||5vw|false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_width_left=&#8220;1px&#8220; border_color_left=&#8220;#bbbbbb&#8220;]<\/p>\n<pre class=\"text\" style=\"font-family: monospace;\">WaitUntil.the(MainUIUtilities.LOADER, WebElementStateMatchers.isVisible());\nWaitUntil.the(MainUIUtilities.LOADER, WebElementStateMatchers.isNotPresent()).\nforNoMoreThan(TimeConstants.SECONDS_10).seconds().performAs(actor);\n <\/pre>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;intro&#8220; _builder_version=&#8220;4.4.6&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;6vh||||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.1em&#8220; text_line_height=&#8220;1.6em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;1.5em&#8220; header_2_line_height=&#8220;0.9em&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2 id=\"Conclusions\">Fazit<\/h2>\n<ul>\n<li>Private Git-Runner m\u00fcssen f\u00fcr die Auftragsausf\u00fchrung registriert warden<\/li>\n<li>Minio kann als Pipeline-Cache-Provider verwendet warden<\/li>\n<li>Bei den End-to-End-Tests muss ein eigenes GitLab-Projekt eingerichtet werden.<\/li>\n<li>Die Ausf\u00fchrung kann von einem beliebigen Projekt aus einer in der Datei gitlab-ci.yml definierten Phase ausgel\u00f6st werden, indem das Container-Image pipeline-trigger verwendet wird.<\/li>\n<li>Die Tests sollten in einer dedizierten\/provisionierten Umgebung ausgef\u00fchrt werden, die zur besseren Stabilit\u00e4t von externen Einfl\u00fcssen isoliert ist.<\/li>\n<li>GitLab-API kann f\u00fcr komplexe Situationen genutzt warden<\/li>\n<li>Die Tests sollten in unabh\u00e4ngige Testsuiten aufgeteilt werden, die parallel laufen m\u00fcssen, ohne Kopf, nur mit Screenshots bei Fehlern, um die beste Leistung zu erreichen<\/li>\n<li>User journeys must be defined to test only the business-critical happy paths.<\/li>\n<li>Die Backend-Integrationstests k\u00f6nnen verwendet werden, um die Daten f\u00fcr die End-to-End-Tests aufzuf\u00fcllen.<\/li>\n<li>F\u00fcr die Wartbarkeit m\u00fcssen \u00fcberall in der UI ids verwendet werden, zus\u00e4tzlich zu den Praktiken der Code\u00fcberpr\u00fcfung und der Wiederverwendung von Code.<\/li>\n<li>Warten auf Bedingung, mit einem Timeout, muss anstelle einer festen Wartezeit verwendet werden.<\/li>\n<li>Eine Bereinigung der Testdaten sollte bei jedem Run durchgef\u00fchrt werden<\/li>\n<\/ul>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; _builder_version=&#8220;4.4.1&#8243; custom_padding=&#8220;|||0px||&#8220; locked=&#8220;off&#8220;][et_pb_row use_custom_gutter=&#8220;on&#8220; gutter_width=&#8220;3&#8243; admin_label=&#8220;\uff3f&#8220; _builder_version=&#8220;4.4.6&#8243; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;4vh||8vh||false|false&#8220; border_color_left=&#8220;rgba(0,0,0,0)&#8220;][et_pb_column type=&#8220;4_4&#8243; _builder_version=&#8220;4.4.6&#8243;][et_pb_text _builder_version=&#8220;4.4.6&#8243; text_font=&#8220;|300|||||||&#8220; text_font_size=&#8220;1.12em&#8220; text_line_height=&#8220;1.55em&#8220; quote_font=&#8220;|700|||||||&#8220; quote_text_align=&#8220;left&#8220; quote_font_size=&#8220;16px&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;30px&#8220; header_3_font_size=&#8220;23px&#8220; header_4_font=&#8220;||||||||&#8220; header_4_font_size=&#8220;16px&#8220; header_4_line_height=&#8220;1.5em&#8220; header_5_font_size=&#8220;14px&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;||||false|false&#8220; border_color_left=&#8220;#ff6317&#8243;]<\/p>\n<h2>\uff3f<\/h2>\n<p>Wie n\u00e4hern Sie sich End-to-End-Tests \/ Pipeline-Integration? Gibt es Erfahrungen, die Sie teilen m\u00f6chten? <a href=\"https:\/\/berg-software.com\/de\/kontakt-berg-software\/\" target=\"_blank\" rel=\"noopener noreferrer\">Lassen Sie es uns wissen<\/a>!<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; _builder_version=&#8220;3.22&#8243; background_color=&#8220;#eeeeee&#8220; custom_padding=&#8220;50px||50px||false|false&#8220; border_color_top=&#8220;#ff6317&#8243; global_module=&#8220;1642&#8243;][et_pb_row column_structure=&#8220;1_3,1_3,1_3&#8243; _builder_version=&#8220;4.4.1&#8243; custom_padding=&#8220;0px|||||&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;1_3&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_social_media_follow _builder_version=&#8220;4.4.4&#8243; text_orientation=&#8220;left&#8220;][et_pb_social_media_follow_network social_network=&#8220;linkedin&#8220; url=&#8220;https:\/\/www.linkedin.com\/company\/berg-computers-srl\/&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#007bb6&#8243; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]linkedin[\/et_pb_social_media_follow_network] [et_pb_social_media_follow_network social_network=&#8220;twitter&#8220; url=&#8220;https:\/\/twitter.com\/berg_software&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#00aced&#8220; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]twitter[\/et_pb_social_media_follow_network] [et_pb_social_media_follow_network social_network=&#8220;facebook&#8220; url=&#8220;https:\/\/www.facebook.com\/bergCOMPUTERS&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#3b5998&#8243; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]facebook[\/et_pb_social_media_follow_network] [et_pb_social_media_follow_network social_network=&#8220;instagram&#8220; url=&#8220;https:\/\/www.instagram.com\/berg_software\/&#8220; _builder_version=&#8220;4.4.4&#8243; background_color=&#8220;#ea2c59&#8243; follow_button=&#8220;off&#8220; url_new_window=&#8220;on&#8220;]instagram[\/et_pb_social_media_follow_network][\/et_pb_social_media_follow][\/et_pb_column][et_pb_column type=&#8220;1_3&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_post_nav in_same_term=&#8220;on&#8220; show_next=&#8220;off&#8220; _builder_version=&#8220;4.4.1&#8243; title_text_color=&#8220;#ff6317&#8243; custom_padding=&#8220;|25px|||false|false&#8220;][\/et_pb_post_nav][\/et_pb_column][et_pb_column type=&#8220;1_3&#8243; _builder_version=&#8220;4.4.1&#8243;][et_pb_post_nav in_same_term=&#8220;on&#8220; show_prev=&#8220;off&#8220; _builder_version=&#8220;4.4.1&#8243; title_text_color=&#8220;#ff6317&#8243; custom_padding=&#8220;|||25px|false|false&#8220;][\/et_pb_post_nav][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8220;1&#8243; admin_label=&#8220;CONTACT&#8220; _builder_version=&#8220;4.4.1&#8243; background_color=&#8220;#d2d2d2&#8243; custom_padding=&#8220;75px||75px||false|false&#8220; global_module=&#8220;1544&#8243;][et_pb_row column_structure=&#8220;1_4,3_4&#8243; admin_label=&#8220;Service Section Title&#8220; _builder_version=&#8220;4.4.1&#8243; custom_padding=&#8220;||25px||false|false&#8220; animation_direction=&#8220;top&#8220; locked=&#8220;off&#8220;][et_pb_column type=&#8220;1_4&#8243; _builder_version=&#8220;3.25&#8243; custom_padding=&#8220;|||&#8220; custom_padding__hover=&#8220;|||&#8220;][\/et_pb_column][et_pb_column type=&#8220;3_4&#8243; _builder_version=&#8220;3.25&#8243; custom_padding=&#8220;|||&#8220; custom_padding__hover=&#8220;|||&#8220;][et_pb_text _builder_version=&#8220;4.4.1&#8243; text_font=&#8220;|300|||||||&#8220; text_text_color=&#8220;#ffffff&#8220; text_line_height=&#8220;1.1em&#8220; header_5_font=&#8220;|600|||||||&#8220; header_5_text_color=&#8220;#ffffff&#8220; header_5_font_size=&#8220;14px&#8220; header_5_line_height=&#8220;1.5em&#8220; custom_margin=&#8220;||||false|false&#8220;]29 Jahre im Gesch\u00e4ft | 2700 Software-Projekte | 760 Kunden | 24 L\u00e4nder<\/p>\n<h5>Wir verwandeln Ideen in Software. Wie lautet Ihre Idee?<\/h5>\n<p>[\/et_pb_text][et_pb_text admin_label=&#8220;Title&#8220; _builder_version=&#8220;4.4.6&#8243; header_text_align=&#8220;center&#8220; header_2_font=&#8220;|300|||||||&#8220; header_2_text_align=&#8220;left&#8220; header_2_text_color=&#8220;#ff6317&#8243; header_2_font_size=&#8220;50px&#8220; header_2_line_height=&#8220;0.9em&#8220; custom_margin=&#8220;||||false|false&#8220; custom_padding=&#8220;25px||25px||false|false&#8220;]<\/p>\n<h2 id=\"Getintouch\">Kontakt aufnehmen<\/h2>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row column_structure=&#8220;1_4,3_4&#8243; _builder_version=&#8220;4.4.4&#8243;][et_pb_column type=&#8220;1_4&#8243; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_column][et_pb_column type=&#8220;3_4&#8243; _builder_version=&#8220;4.4.4&#8243;][et_pb_contact_form email=&#8220;contact@bergsoftprod.wpengine.com&#8220; custom_message=&#8220;WEBFORM MESSAGE||et_pb_line_break_holder||\uff3f||et_pb_line_break_holder||FROM: %%Name%%||et_pb_line_break_holder||EMAIL: %%Email%%||et_pb_line_break_holder||PHONE NUMBER: %%Phone_number%%||et_pb_line_break_holder||COMPANY: %%Company_name%%||et_pb_line_break_holder||TERMS &amp; CONDITIONS: %%Terms_and_Conditions%%||et_pb_line_break_holder||DATA PRIVACY POLICY: %%Data_Privacy_Policy%%||et_pb_line_break_holder||\uff3f||et_pb_line_break_holder||MESSAGE:||et_pb_line_break_holder||%%Message%%&#8220; success_message=&#8220;Thank you for reaching out! Your message was sent. We will get back to you right away.&#8220; _builder_version=&#8220;4.4.4&#8243; form_field_background_color=&#8220;#d2d2d2&#8243; form_field_text_color=&#8220;#ffffff&#8220; form_field_focus_background_color=&#8220;#ffffff&#8220; form_field_focus_text_color=&#8220;#000000&#8243; title_level=&#8220;h2&#8243; title_font=&#8220;|300|||||||&#8220; title_text_color=&#8220;#ff6317&#8243; title_font_size=&#8220;30px&#8220; form_field_line_height=&#8220;1.5em&#8220; custom_button=&#8220;on&#8220; button_text_size=&#8220;14px&#8220; button_text_color=&#8220;#ffffff&#8220; button_bg_color=&#8220;#ff6317&#8243; button_border_width=&#8220;0px&#8220; button_border_radius=&#8220;0px&#8220; button_icon=&#8220;%%3%%&#8220; button_on_hover=&#8220;off&#8220; border_color_all=&#8220;#ffffff&#8220; border_width_bottom=&#8220;1px&#8220;][et_pb_contact_field field_id=&#8220;Name&#8220; field_title=&#8220;Name *&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243; form_field_background_color=&#8220;#d2d2d2&#8243; form_field_text_color=&#8220;#ffffff&#8220; form_field_focus_background_color=&#8220;#ffffff&#8220; form_field_focus_text_color=&#8220;#000000&#8243; border_width_bottom=&#8220;1px&#8220; button_text_size__hover_enabled=&#8220;off&#8220; button_one_text_size__hover_enabled=&#8220;off&#8220; button_two_text_size__hover_enabled=&#8220;off&#8220; button_text_color__hover_enabled=&#8220;off&#8220; button_one_text_color__hover_enabled=&#8220;off&#8220; button_two_text_color__hover_enabled=&#8220;off&#8220; button_border_width__hover_enabled=&#8220;off&#8220; button_one_border_width__hover_enabled=&#8220;off&#8220; button_two_border_width__hover_enabled=&#8220;off&#8220; button_border_color__hover_enabled=&#8220;off&#8220; button_one_border_color__hover_enabled=&#8220;off&#8220; button_two_border_color__hover_enabled=&#8220;off&#8220; button_border_radius__hover_enabled=&#8220;off&#8220; button_one_border_radius__hover_enabled=&#8220;off&#8220; button_two_border_radius__hover_enabled=&#8220;off&#8220; button_letter_spacing__hover_enabled=&#8220;off&#8220; button_one_letter_spacing__hover_enabled=&#8220;off&#8220; button_two_letter_spacing__hover_enabled=&#8220;off&#8220; button_bg_color__hover_enabled=&#8220;off&#8220; button_one_bg_color__hover_enabled=&#8220;off&#8220; button_two_bg_color__hover_enabled=&#8220;off&#8220;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Email&#8220; field_title=&#8220;E-Mail-Adresse *&#8220; field_type=&#8220;email&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243; button_text_size__hover_enabled=&#8220;off&#8220; button_one_text_size__hover_enabled=&#8220;off&#8220; button_two_text_size__hover_enabled=&#8220;off&#8220; button_text_color__hover_enabled=&#8220;off&#8220; button_one_text_color__hover_enabled=&#8220;off&#8220; button_two_text_color__hover_enabled=&#8220;off&#8220; button_border_width__hover_enabled=&#8220;off&#8220; button_one_border_width__hover_enabled=&#8220;off&#8220; button_two_border_width__hover_enabled=&#8220;off&#8220; button_border_color__hover_enabled=&#8220;off&#8220; button_one_border_color__hover_enabled=&#8220;off&#8220; button_two_border_color__hover_enabled=&#8220;off&#8220; button_border_radius__hover_enabled=&#8220;off&#8220; button_one_border_radius__hover_enabled=&#8220;off&#8220; button_two_border_radius__hover_enabled=&#8220;off&#8220; button_letter_spacing__hover_enabled=&#8220;off&#8220; button_one_letter_spacing__hover_enabled=&#8220;off&#8220; button_two_letter_spacing__hover_enabled=&#8220;off&#8220; button_bg_color__hover_enabled=&#8220;off&#8220; button_one_bg_color__hover_enabled=&#8220;off&#8220; button_two_bg_color__hover_enabled=&#8220;off&#8220;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Phone_number&#8220; field_title=&#8220;Telefonnummer&#8220; required_mark=&#8220;off&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Company_name&#8220; field_title=&#8220;Name des Unternehmens&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Message&#8220; field_title=&#8220;Nachricht *&#8220; field_type=&#8220;text&#8220; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243; form_field_background_color=&#8220;#d2d2d2&#8243; form_field_focus_background_color=&#8220;#ffffff&#8220; form_field_focus_text_color=&#8220;#000000&#8243; border_width_bottom=&#8220;1px&#8220; button_text_size__hover_enabled=&#8220;off&#8220; button_one_text_size__hover_enabled=&#8220;off&#8220; button_two_text_size__hover_enabled=&#8220;off&#8220; button_text_color__hover_enabled=&#8220;off&#8220; button_one_text_color__hover_enabled=&#8220;off&#8220; button_two_text_color__hover_enabled=&#8220;off&#8220; button_border_width__hover_enabled=&#8220;off&#8220; button_one_border_width__hover_enabled=&#8220;off&#8220; button_two_border_width__hover_enabled=&#8220;off&#8220; button_border_color__hover_enabled=&#8220;off&#8220; button_one_border_color__hover_enabled=&#8220;off&#8220; button_two_border_color__hover_enabled=&#8220;off&#8220; button_border_radius__hover_enabled=&#8220;off&#8220; button_one_border_radius__hover_enabled=&#8220;off&#8220; button_two_border_radius__hover_enabled=&#8220;off&#8220; button_letter_spacing__hover_enabled=&#8220;off&#8220; button_one_letter_spacing__hover_enabled=&#8220;off&#8220; button_two_letter_spacing__hover_enabled=&#8220;off&#8220; button_bg_color__hover_enabled=&#8220;off&#8220; button_one_bg_color__hover_enabled=&#8220;off&#8220; button_two_bg_color__hover_enabled=&#8220;off&#8220;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Terms_and_Conditions&#8220; field_title=&#8220; &#8220; field_type=&#8220;checkbox&#8220; checkbox_options=&#8220;%91{%22value%22:%22Ich habe die AGB gelesen und akzeptiert%22,%22checked%22:0,%22dragID%22:-1}%93&#8243; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][et_pb_contact_field field_id=&#8220;Data_Privacy_Policy&#8220; field_title=&#8220; &#8220; field_type=&#8220;checkbox&#8220; checkbox_options=&#8220;%91{%22value%22:%22Ich habe die Datenschutzrichtlinie gelesen und akzeptiert%22,%22checked%22:0,%22dragID%22:-1}%93&#8243; fullwidth_field=&#8220;on&#8220; _builder_version=&#8220;4.4.4&#8243;][\/et_pb_contact_field][\/et_pb_contact_form][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>End-to-End-Tests sind ein Sicherheitsnetz zur Steigerung der Softwarequalit\u00e4t. Wir besprechen Entwicklung, Wartung und Gitlab-Integration.<\/p>\n","protected":false},"author":12,"featured_media":6307,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[79,141],"tags":[],"class_list":["post-7474","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-einblicke","category-how-to-de"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v16.1.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>End-to-end tests &amp; GitLab Integration | Berg Software<\/title>\n<meta name=\"description\" content=\"End-to-End-Tests sind ein Sicherheitsnetz zur Steigerung der Softwarequalit\u00e4t. Wir besprechen Entwicklung, Wartung und Gitlab-Integration.\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"End-to-end tests &amp; GitLab Integration | Berg Software\" \/>\n<meta property=\"og:description\" content=\"End-to-End-Tests sind ein Sicherheitsnetz zur Steigerung der Softwarequalit\u00e4t. Wir besprechen Entwicklung, Wartung und Gitlab-Integration.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/\" \/>\n<meta property=\"og:site_name\" content=\"Berg Software\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/bergCOMPUTERS\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-05-17T15:39:49+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-05-17T15:45:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-00-Cover.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@berg_software\" \/>\n<meta name=\"twitter:site\" content=\"@berg_software\" \/>\n<meta name=\"twitter:label1\" content=\"Gesch\u00e4tzte Lesezeit\">\n\t<meta name=\"twitter:data1\" content=\"98 Minuten\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#organization\",\"name\":\"Berg Software\",\"url\":\"https:\/\/www.berg-software.com\/en\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/bergCOMPUTERS\/\",\"https:\/\/www.instagram.com\/berg_software\/\",\"https:\/\/www.linkedin.com\/company\/berg-computers-srl\/\",\"https:\/\/www.youtube.com\/channel\/UCw1FfcRJnC-CoKPwlcM10Iw\",\"https:\/\/twitter.com\/berg_software\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#logo\",\"inLanguage\":\"de-DE\",\"url\":\"https:\/\/berg-software.com\/wp-content\/uploads\/berg-software-logo.png\",\"contentUrl\":\"https:\/\/berg-software.com\/wp-content\/uploads\/berg-software-logo.png\",\"width\":512,\"height\":512,\"caption\":\"Berg Software\"},\"image\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#website\",\"url\":\"https:\/\/www.berg-software.com\/en\/\",\"name\":\"Berg Software\",\"description\":\"We turn ideas into software.\",\"publisher\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/www.berg-software.com\/en\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de-DE\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#primaryimage\",\"inLanguage\":\"de-DE\",\"url\":\"https:\/\/www.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-00-Cover.jpg\",\"contentUrl\":\"https:\/\/www.berg-software.com\/wp-content\/uploads\/Berg-Software-End-to-end-tests-an-GitLab-integration-00-Cover.jpg\",\"width\":1200,\"height\":600,\"caption\":\"Berg Software - End-to-end tests an GitLab integration - 00 Cover\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#webpage\",\"url\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/\",\"name\":\"End-to-end tests & GitLab Integration | Berg Software\",\"isPartOf\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#primaryimage\"},\"datePublished\":\"2021-05-17T15:39:49+00:00\",\"dateModified\":\"2021-05-17T15:45:08+00:00\",\"description\":\"End-to-End-Tests sind ein Sicherheitsnetz zur Steigerung der Softwarequalit\\u00e4t. Wir besprechen Entwicklung, Wartung und Gitlab-Integration.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#breadcrumb\"},\"inLanguage\":\"de-DE\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/\",\"url\":\"https:\/\/www.berg-software.com\/de\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/category\/einblicke\/\",\"url\":\"https:\/\/www.berg-software.com\/de\/category\/einblicke\/\",\"name\":\"Einblicke\"}},{\"@type\":\"ListItem\",\"position\":3,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/\",\"url\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/\",\"name\":\"End-to-End-Tests Reise &amp; Integration in eine GitLab-Pipeline\"}}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#webpage\"},\"author\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#\/schema\/person\/4becfb1c9de08963757e6dc8531fef1a\"},\"headline\":\"End-to-End-Tests Reise &amp; Integration in eine GitLab-Pipeline\",\"datePublished\":\"2021-05-17T15:39:49+00:00\",\"dateModified\":\"2021-05-17T15:45:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#webpage\"},\"publisher\":{\"@id\":\"https:\/\/www.berg-software.com\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.berg-software.com\/de\/end-to-end-tests-reise-integration-in-eine-gitlab-pipeline\/#primaryimage\"},\"articleSection\":\"Einblicke,How to\",\"inLanguage\":\"de-DE\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.berg-software.com\/en\/#\/schema\/person\/4becfb1c9de08963757e6dc8531fef1a\",\"name\":\"Ionu\\u021b Bucurescu\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/posts\/7474","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/comments?post=7474"}],"version-history":[{"count":0,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/posts\/7474\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/media\/6307"}],"wp:attachment":[{"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/media?parent=7474"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/categories?post=7474"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.berg-software.com\/de\/wp-json\/wp\/v2\/tags?post=7474"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}