1. Was ist Continuous Testing?
Unter Continuous Testing versteht man einen Prozess, bei dem automatisiertes Feedback in verschiedenen Phasen des Softwareentwicklungslebenszyklus (Software Development Life Cycle, SDLC) integriert wird, um die Geschwindigkeit und Effizienz bei der Verwaltung von Bereitstellungen zu verbessern.
Was sind kontinuierliche Tests?

2. Hauptkomponenten von Continuous Testing
-
Integration in CI/CD-Pipelines: Tests werden nahtlos in Continuous Integration (CI) und Continuous Delivery (CD) Pipelines eingebunden, um bei jedem Code-Commit eine sofortige Qualitätsbewertung zu ermöglichen. So wird sichergestellt, dass Fehler frühzeitig erkannt und behoben werden können.
-
Stabile Testumgebungen: Die Bereitstellung konsistenter und produktionsähnlicher Testumgebungen stellt sicher, dass Testergebnisse zuverlässig und aussagekräftig sind. Inkonsistenzen zwischen Test- und Produktionsumgebungen können zu unerwarteten Problemen führen.
4. Arten von Tests im Continuous Testing
-
Unit-Tests: Überprüfung einzelner Codeeinheiten (z.B. Methoden, Klassen) auf korrekte Funktionalität, um sicherzustellen, dass jede Einheit isoliert betrachtet funktioniert.
-
Integrationstests: Testen des Zusammenspiels verschiedener Module oder Services, um zu gewährleisten, dass sie korrekt miteinander kommunizieren und Daten austauschen.
-
End-to-End-Tests (E2E-Tests): Validierung kompletter Geschäftsprozesse vom Anfang bis zum Ende (z.B. Benutzeranmeldung, Produktsuche, Kaufabschluss), um das Systemverhalten aus Anwendersicht zu prüfen.
-
Leistungstests (Performance Tests): Bewertung der Performance (z.B. Reaktionszeit, Durchsatz) der Anwendung unter verschiedenen Lastbedingungen, um sicherzustellen, dass sie auch bei hoher Auslastung stabil bleibt.
-
Sicherheitstests: Identifizierung und Behebung von Sicherheitslücken innerhalb der Anwendung, um sie vor Angriffen und unbefugtem Zugriff zu schützen.
-
UI-Tests (User Interface Tests): Automatisierte Tests der Benutzeroberfläche, um die korrekte Darstellung und Funktionalität der Anwendung aus Sicht des Endbenutzers zu verifizieren.
5. Herausforderungen beim Continuous Testing
-
Testdatenmanagement: Die Bereitstellung und Pflege geeigneter, konsistenter und datenschutzkonformer Testdaten kann komplex und zeitaufwändig sein.
-
Infrastrukturkosten: Der Aufbau und die Wartung der notwendigen Testinfrastruktur (z.B. Server, Datenbanken, virtuelle Maschinen) erfordern Investitionen und Ressourcen.
-
Testwartung: Automatisierte Tests müssen regelmäßig aktualisiert werden, um mit Änderungen im Code, der Architektur und den Anforderungen Schritt zu halten. Veraltete Tests können zu falschen Ergebnissen führen.
-
Komplexität der Testumgebung: Das Aufsetzen einer stabilen Testumgebung, die der Produktivumgebung gleicht, ist eine Herausforderung
-
Zeitaufwand: Das Ausführen aller Tests kann bei größeren Projekten viel Zeit in Anspruch nehmen
6. Überblick: Testframeworks und ihre Einsatzbereiche
Tool | Open Source | Lizenz | Einsatzbereiche | Sprachen |
---|---|---|---|---|
Selenium |
Ja |
Apache 2.0 |
UI-Tests, Web-Automatisierung |
Java, Python, C#, JavaScript, Ruby |
JUnit |
Ja |
Eclipse Public v2.0 |
Unit-Tests |
Java |
TestNG |
Ja |
Apache 2.0 |
Unit-, Integrationstests, End-to-End-Tests |
Java |
Cypress |
Ja |
MIT |
End-to-End-Webtests |
JavaScript |
JMeter |
Ja |
Apache 2.0 |
Last-, Performance-, Stresstests |
Java |
SonarQube |
Teilweise |
LGPLv3/Proprietär |
Code-Analyse, Sicherheitsprüfung |
25+ Sprachen (Java, C#, Python, etc.) |
Rest-Assured |
Ja |
Apache 2.0 |
API-Tests (REST-Services) |
Java |
Mockito |
Ja |
MIT |
Mocking für Unit- und Integrationstests |
Java |
7. Continuous Testing in Quarkus
Quarkus unterstützt Continuous Testing, eine Funktion, die es ermöglicht, Tests unmittelbar nach dem Speichern von Codeänderungen auszuführen. Dies beschleunigt den Entwicklungsprozess erheblich, da Entwickler sofortiges Feedback zu ihren Änderungen erhalten.
8. Funktionsweise von Continuous Testing in Quarkus
-
Automatische Testausführung: Quarkus führt Tests automatisch aus, wenn Änderungen erkannt werden.
-
Entwicklungsmodus: Im Entwicklungsmodus (
quarkus dev
) sind Tests standardmäßig pausiert. Mit der Taster
können Tests manuell gestartet werden, wobei die Ergebnisse sofort angezeigt werden. -
Konfigurationsoptionen: Das Verhalten von Continuous Testing kann in der
application.properties
-Datei angepasst werden:-
quarkus.test.continuous-testing=enabled
: Aktiviert automatisches Testen bei jeder Änderung. -
quarkus.test.continuous-testing=paused
: Deaktiviert automatisches Testen; Tests müssen manuell gestartet werden.
-
-
Interaktive Steuerung im Entwicklungsmodus: Verschiedene Befehle stehen zur Verfügung, um das Testen effizient zu steuern:
-
r
: Alle Tests erneut ausführen. -
f
: Nur fehlgeschlagene Tests erneut ausführen. -
b
: Zwischen allen Tests und fehlgeschlagenen Tests umschalten. -
v
: Fehlerdetails anzeigen. -
p
: Tests pausieren. -
i
: Zusätzliche Testinformationen anzeigen. -
h
: Hilfe anzeigen. -
q
: Entwicklungsmodus beenden.
-
Mit diesen Funktionen unterstützt Quarkus eine schnelle Rückmeldung während der Entwicklung und erleichtert das kontinuierliche Testen.
9. Demo
Im Repository 01-referate-balintb4 finden Sie neben dieser Dokumentation zwei Demo-Projekte.
Beide Projekte nutzen GitHub Actions, um Tests automatisiert auszuführen. Es handelt sich um zwei identische Projekte, wobei eines DevServices und das andere eine manuell konfigurierte PostgreSQL-Datenbank verwendet.
-
continuous-testing-demo
: Beinhaltet eine klassische PostgreSQL-Konfiguration. -
devservices-demo
: Nutzt Quarkus Dev Services zu Testzwecken.
9.1. Hauptunterschiede in der GitHub Actions Konfiguration
Der Hauptunterschied zwischen den beiden Projekten liegt in der Art und Weise, wie die PostgreSQL-Datenbank für die Tests bereitgestellt wird. Das Projekt continuous-testing-demo
erfordert manuelle Schritte, die im Folgenden in der Workflow-Datei dargestellt sind:
name: Run all test in continuous-testing-demo project
on:
push:
paths:
- 'continuous-testing-demo/**'
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
build-backend:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: KengoTODA/actions-setup-docker-compose@v1 (1)
with:
version: '2.14.2'
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: 'maven'
cache-dependency-path: 'continuous-testing-demo/pom.xml'
- name: Start PostgreSQL Database (2)
run: docker compose -f docker-compose-db.yml up -d
- name: Wait for database to be ready (3)
run: |
until docker compose -f docker-compose-db.yml exec db pg_isready; do
echo "Waiting for database to be ready..."
sleep 1
done
- name: Set execute permission for the test script
run: chmod +x .github/cicd/continous-testing-demo-scripts/run-test.sh
- name: Execute test script (4)
env: # Setze Umgebungsvariablen für die Verbindung zur DB
SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/db
SPRING_DATASOURCE_USERNAME: app
SPRING_DATASOURCE_PASSWORD: app
run: .github/cicd/continous-testing-demo-scripts/run-test.sh
1 | Auf dem GitHub Actions Runner muss das docker-compose -Plugin manuell installiert werden. |
2 | Das PostgreSQL-Image muss manuell mit docker compose gestartet werden. |
3 | Es muss gewartet werden, bis die Datenbank vollständig initialisiert und einsatzbereit ist. |
4 | Die Umgebungsvariablen für die Datenbankverbindung müssen explizit gesetzt werden. |
Wichtige Information zur
docker-compose-db.yml Die |
Im Folgenden sehen Sie den Inhalt der docker-compose-db.yml
-Datei, die in diesem Projekt verwendet wird:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3.8'
services:
db:
image: postgres:17.0-alpine
restart: unless-stopped
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: db
ports:
- 5432:5432
networks:
- postgres
networks:
postgres:
driver: bridge
Im Gegensatz dazu verwendet das Projekt devservices-demo
die Quarkus Dev Services. Dies vereinfacht die Konfiguration erheblich, da Quarkus die Datenbank automatisch startet und verwaltet. Sie müssen sich nicht um die manuelle Installation von docker-compose
, das Starten der Datenbank oder das Setzen der Umgebungsvariablen kümmern.
10. Fazit
Continuous Testing ist ein mächtiger Ansatz, um die Qualität von Software zu verbessern und die Entwicklungszeit zu verkürzen. Durch die Automatisierung von Tests und die Integration in CI/CD-Pipelines wird sichergestellt, dass Fehler frühzeitig erkannt und behoben werden können. Quarkus bietet mit seinem Continuous-Testing-Feature eine hervorragende Unterstützung für diesen Ansatz.
11. Anhang
11.1. Glossar
-
CI/CD: Continuous Integration/Continuous Delivery bzw. Continuous Deployment.
-
SDLC: Software Development Life Cycle (Softwareentwicklungslebenszyklus).
-
Unit-Test: Test einer einzelnen Codeeinheit (z.B. Methode, Klasse).
-
Integrationstest: Test des Zusammenspiels mehrerer Komponenten.
-
End-to-End-Test (E2E-Test): Test eines kompletten Anwendungsfalls aus Sicht des Endbenutzers.
-
Performance Test: Test zur Überprüfung der Leistungsfähigkeit einer Anwendung.
-
Sicherheitstest: Test zur Identifizierung von Sicherheitslücken.
11.2. Häufig gestellte Fragen (FAQ)
-
Frage: Was ist der Unterschied zwischen Continuous Testing und traditionellem Testen?
-
Antwort: Beim traditionellen Testen werden Tests oft in einer separaten Phase nach der Entwicklung durchgeführt. Continuous Testing integriert Tests in jede Phase des Entwicklungszyklus und ermöglicht so ein früheres und häufigeres Feedback.
-
Frage: Welche Vorteile bietet Continuous Testing?
-
Antwort: Schnellere Feedback-Zyklen, frühere Fehlererkennung, verbesserte Codequalität, erhöhte Effizienz, beschleunigte Bereitstellung.
-
Frage: Ist Continuous Testing für jedes Projekt geeignet?
-
Antwort: Continuous Testing ist besonders für Projekte mit häufigen Codeänderungen und einem hohen Automatisierungsgrad geeignet. Bei kleineren, weniger komplexen Projekten kann der Aufwand für die Implementierung den Nutzen übersteigen.
Quarkus-Anwendung mit PostgreSQL und Dev Services
:imagesdir:asciidocs/docs/images :source-highlighter: rouge :docinfo: shared
12. Einleitung
12.1. Was sind Devservices?
Quarkus Dev Services sind eine neue Funktion von Quarkus, die es Entwicklern ermöglicht, bestimmte Entwicklungsdienste (wie Datenbanken, Message-Broker oder andere Infrastrukturkomponenten) automatisch und ohne zusätzliche manuelle Einrichtung zu starten. Diese Dienste laufen in Containern (normalerweise über Docker oder Podman) und werden nahtlos in die Entwicklungsumgebung integriert.
12.2. Vorteile von Quarkus Dev Services
-
Automatisches Setup:
-
Dev Services starten automatisch die benötigten Dienste, z. B. eine Datenbank, sobald die Anwendung sie braucht.
-
Dadurch spart man Zeit und musst man keine separaten Container oder Konfigurationen manuell einrichten.
-
-
Nahtlose Integration:
-
Die gestarteten Dienste sind direkt in die Anwendung eingebunden und werden automatisch mit den passenden Konfigurationswerten versorgt.
-
13. Voraussetzungen
Bevor du beginnst, stelle sicher, dass du die folgenden Tools installiert hast:
-
Java 17 oder höher
-
Maven
-
Docker (für die Ausführung von Dev Services)
-
PostgreSQL (für den direkten Zugriff, wenn nötig)
14. Projekt erstellen
Erstellen Sie ein neues Quarkus-Projekt mit den notwendigen Erweiterungen, indem Sie den folgenden Befehl in Ihrem Terminal ausführen:
mvn io.quarkus.platform:quarkus-maven-plugin:3.6.4:create \
-DprojectGroupId=com.example \
-DprojectArtifactId=quarkus-postgres-app \
-DclassName="com.example.resource.PersonResource" \
-Dextensions="resteasy-jackson,hibernate-orm-panache,jdbc-postgresql"
cd quarkus-postgres-app
Dieser Befehl erstellt ein neues Quarkus-Projekt mit:
-
resteasy-jackson
: Für die Serialisierung und Deserialisierung von JSON in den REST-Endpunkten. -
hibernate-orm-panache
: Für die Datenbankinteraktion mit Panache. -
jdbc-postgresql
: Für die Verbindung zur PostgreSQL-Datenbank.
15. Abhängigkeiten
Stelle sicher, dass die folgenden Abhängigkeiten in deiner pom.xml (für Maven) enthalten sind:
<dependencies>
<!-- Quarkus RESTEasy für REST APIs -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<!-- Quarkus Hibernate ORM für die Datenbankintegration -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<!-- PostgreSQL JDBC-Treiber -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>
16. Konfiguration der PostgreSQL-Datenbank
Quarkus Dev Services
wird automatisch eine PostgreSQL-Datenbank für dich starten.
Du musst jedoch die Verbindungsdetails in der Konfiguration festlegen.
Öffne die Datei src/main/resources/application.properties
und füge die folgenden Konfigurationen hinzu:
16.1. Quarkus Datenbank Konfiguration
quarkus.datasource.db-kind=postgresql (1)
quarkus.datasource.username=your_username (2)
quarkus.datasource.password=your_password (3)
quarkus.hibernate-orm.database.generation=update (4)
quarkus.hibernate-orm.log.sql=true (5)
quarkus.hibernate-orm.log.format-sql=true (6)
quarkus.datasource.devservices.enabled=true (7)
quarkus.datasource.devservices.image-name=postgres:latest (8)
Erklärung:
1 | Gibt an, dass PostgreSQL als Datenbank verwendet wird. |
2 | (Optional) Der Benutzername für den PostgreSQL-Datenbankzugriff. |
3 | (Optional) Das Passwort für den PostgreSQL-Datenbankzugriff. |
4 | (Optional) Sagt Hibernate, dass es die Datenbankstruktur beim Start aktualisieren soll. |
5 | (Optional) Aktiviert das SQL-Logging, damit SQL-Abfragen im Log sichtbar sind. |
6 | (Optional) Formatiert SQL-Abfragen für bessere Lesbarkeit im Log. |
7 | Aktiviert Dev Services, die eine Datenbank im Docker-Container starten. |
8 | Gibt das Docker-Image für PostgreSQL an, das verwendet werden soll. |
17. Erstellen der Person
-Entität
Nun erstellst du eine Entität, die du in der Datenbank speichern möchtest.
Erstelle die Datei src/main/java/com/example/model/Person.java
:
package com.example.model;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "person")
public class Person extends PanacheEntity {
public String firstName;
public String lastName;
public String email;
public Person() {
}
public Person(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
}
Die Klasse Person erweitert PanacheEntity, wodurch Quarkus automatisch CRUD-Operationen für diese Entität bereitstellt.
18. Erstellen eines REST Endpunkts
Erstelle nun einen REST-Endpunkt, um die Entitäten über eine API verfügbar zu machen. Erstelle die Datei src/main/java/com/example/resource/PersonResource.java:
package com.example.resource;
import com.example.model.Person;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.inject.Inject;
@Path("/persons")
public class PersonResource {
@Inject
PersonRepository personRepository;
@GET
@Path("/all")
@Produces(MediaType.APPLICATION_JSON)
public Response getAllPersons() {
if (personRepository.count() == 0) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(personRepository.findAll()).build();
}
}
Erklärung:
Dieser Endpunkt liefert alle Person-Entitäten als JSON zurück.
19. Optional: Datenbank mit DatabaseSeed initialisieren
Um einige Daten beim Start der Anwendung zu erstellen, kannst du eine DatabaseSeed-Klasse hinzufügen, die beim Start der Anwendung Daten in die Datenbank einfügt.
Erstelle die Datei src/main/java/com/example/DatabaseSeed.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example;
import com.example.model.Person;
import io.quarkus.runtime.StartupEvent;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.transaction.Transactional;
@ApplicationScoped
public class DatabaseSeed {
@Inject
PersonRepository personRepository;
@Transactional
void onStart(@Observes StartupEvent ev) {
if (personRepository.count() == 0) {
personRepository.persist(new Person("John", "Doe", "john.doe@example.com"));
personRepository.persist(new Person("Jane", "Doe", "jane.doe@example.com"));
}
}
}
Erklärung:
Diese Klasse fügt beim Start der Anwendung einige Person-Entitäten hinzu, wenn noch keine vorhanden sind.
21. Zusammenfassung
In dieser Anleitung haben wir eine Quarkus-Anwendung mit einer PostgreSQL-Datenbank erstellt, die von Quarkus Dev Services automatisch verwaltet wird. Wir haben eine einfache REST-API erstellt, um mit der Datenbank zu interagieren, und beim Start der Anwendung einige Daten eingefügt. Die Verwendung von Dev Services macht das Setup der Datenbank sehr einfach, ohne dass du manuell Docker-Container oder PostgreSQL installieren musst.