Der Codest
  • Über uns
  • Dienstleistungen
    • Software-Entwicklung
      • Frontend-Softwareentwicklung
      • Backend-Softwareentwicklung
    • Staff Augmentation
      • Frontend-Entwickler
      • Backend-Entwickler
      • Daten-Ingenieure
      • Cloud-Ingenieure
      • QS-Ingenieure
      • Andere
    • IT-Beratung
      • Prüfung und Beratung
  • Branchen
    • Fintech & Bankwesen
    • E-commerce
    • Adtech
    • Gesundheitstechnik
    • Herstellung
    • Logistik
    • Automobilindustrie
    • IOT
  • Wert für
    • CEO
    • CTO
    • Delivery Manager
  • Unser Team
  • Fallstudien
  • Gewusst wie
    • Blog
    • Begegnungen
    • Webinare
    • Ressourcen
Karriere Kontakt aufnehmen
  • Über uns
  • Dienstleistungen
    • Software-Entwicklung
      • Frontend-Softwareentwicklung
      • Backend-Softwareentwicklung
    • Staff Augmentation
      • Frontend-Entwickler
      • Backend-Entwickler
      • Daten-Ingenieure
      • Cloud-Ingenieure
      • QS-Ingenieure
      • Andere
    • IT-Beratung
      • Prüfung und Beratung
  • Wert für
    • CEO
    • CTO
    • Delivery Manager
  • Unser Team
  • Fallstudien
  • Gewusst wie
    • Blog
    • Begegnungen
    • Webinare
    • Ressourcen
Karriere Kontakt aufnehmen
Pfeil zurück ZURÜCK
2022-07-26
Software-Entwicklung

Testcontainer - Wie kann man Tests vereinfachen?

Bartlomiej Kuczynski

Suchen Sie nach einer Möglichkeit, Tests auf einfachere Weise zu erstellen? Wir haben Sie! Lesen Sie den folgenden Artikel und erfahren Sie, wie Sie es möglich machen.

Die moderne Anwendungsentwicklung basiert auf einer einfachen Regel:

Zusammensetzung verwenden

Wir fügen Klassen, Funktionen und Dienste zu größeren Softwareteilen zusammen. Dieses letzte Element ist die Grundlage von Microservices und sechseckige Architektur. Wir möchten bestehende Lösungen nutzen, sie in unsere Software integrieren und direkt auf den Markt gehen. Markt.

Möchten Sie die Kontoregistrierung abwickeln und Benutzerdaten speichern? Sie können einen der OAuth-Dienste wählen. Vielleicht bietet Ihre Anwendung eine Art von Abonnement oder Zahlung an? Es gibt viele Dienste, die Ihnen bei dieser Aufgabe helfen können. Benötigen Sie Analysen für Ihre Website, verstehen aber die GDPR nicht? Nehmen Sie doch einfach eine der fertigen Lösungen.

Etwas, das die Entwicklung aus geschäftlicher Sicht so einfach macht, kann Ihnen Kopfschmerzen bereiten - nämlich dann, wenn Sie einen einfachen Test schreiben müssen.

Die Phantastischen Tierwesen: Warteschlangen, Datenbanken und wie man sie testet

Unit-Tests sind ziemlich einfach. Wenn Sie nur die Regeln befolgen, dann werden Ihre Testumgebung und Code gesund sind. Welche Regeln sind das?

  • Leicht zu schreiben - ein Unit-Test sollte einfach zu schreiben sein, weil man viele davon schreibt. Weniger Aufwand bedeutet, dass mehr Tests geschrieben werden.
  • Lesbar - der Testcode sollte leicht zu lesen sein. Der Test ist eine Geschichte. Er beschreibt das Verhalten der Software und kann als Abkürzung für die Dokumentation verwendet werden. Ein guter Unit-Test hilft Ihnen, Fehler zu beheben, ohne den Code zu debuggen.
  • Zuverlässig - der Test sollte nur dann fehlschlagen, wenn das getestete System einen Fehler aufweist. Offensichtlich? Nicht immer. Manchmal bestehen Tests, wenn Sie sie einzeln ausführen, aber sie schlagen fehl, wenn Sie sie als Gruppe ausführen. Sie funktionieren auf Ihrem Rechner, aber nicht auf dem CI (Funktioniert auf meinem Rechner). Bei einem guten Einheitstest gibt es nur einen Grund für ein Scheitern.
  • Schnell - Tests sollten schnell sein. Die Vorbereitung, der Start und die Testausführung selbst sollten sehr schnell gehen. Andernfalls werden Sie sie zwar schreiben, aber nicht ausführen. Langsame Tests bedeuten, dass man den Fokus verliert. Man wartet und schaut auf den Fortschrittsbalken.
  • Unabhängig - Schließlich sollte der Test unabhängig sein. Diese Regel ergibt sich aus den vorangegangenen. Nur wirklich unabhängige Tests können eine Einheit bilden. Sie stören sich nicht gegenseitig, können in beliebiger Reihenfolge ausgeführt werden und mögliche Fehler hängen nicht von den Ergebnissen anderer Tests ab. Unabhängig bedeutet auch, dass sie nicht von externen Ressourcen wie Datenbanken, Nachrichtendiensten oder dem Dateisystem abhängig sind. Wenn Sie mit externen Ressourcen kommunizieren müssen, können Sie Mocks, Stubs oder Dummys verwenden.

Kompliziert wird es, wenn wir einige Integrationstests schreiben wollen. Es ist nicht schlimm, wenn wir ein paar Dienste zusammen testen wollen. Aber wenn wir Dienste testen müssen, die externe Ressourcen wie Datenbanken oder Nachrichtendienste nutzen, dann ist das ein Problem.

Um den Test durchführen zu können, müssen Sie die...

Vor vielen Jahren, als wir Integrationstests durchführen und z. B. Datenbanken verwenden wollten, hatten wir zwei Möglichkeiten:

  1. Wir können eine Datenbank lokal installieren. Richten Sie ein Schema ein und verbinden Sie sich von unserem Test aus;
  2. Wir können eine Verbindung zu einer bestehenden Instanz "irgendwo im Weltraum" herstellen.

Beide hatten Vor- und Nachteile. Aber beide führen zusätzliche Ebenen der Komplexität ein. Manchmal handelte es sich um technische Komplexität, die sich aus den Merkmalen bestimmter Tools ergab, z. B. die Installation und Verwaltung der Oracle-DB auf Ihrem lokalen Rechner. Manchmal war es eine Unannehmlichkeit im Prozess, z. B. müssen Sie mit dem Test einverstanden sein Team über die JMS-Nutzung... jedes Mal, wenn Sie Tests durchführen wollen.

Container als Retter in der Not

In den letzten 10 Jahren hat sich die Idee der Containerisierung in der Branche durchgesetzt. Daher war es naheliegend, die Container als Lösung für unser Integrationstestproblem zu wählen. Dies ist eine einfache, saubere Lösung. Sie führen einfach Ihren Prozess-Build aus und alles funktioniert! Sie können es nicht glauben? Werfen Sie einen Blick auf diese einfache Konfiguration eines Maven-Builds:

com.dkanejs.maven.plugins
     docker-compose-maven-plugin
     4.0.0
     
       
         up
         test-kompilieren
         
           auf
         
         
           ${Projekt.basedir}/docker-compose.yml
           true
         
       
       
         down
         Post-Integrationstest
         
           abwärts
         
         
           ${project.basedir}/docker-compose.yml
           true

Und die docker-compose.yml Die Datei sieht auch ziemlich gut aus!

Version: "3.5"

Dienste:

 postgres:
   container_name: reactivedb
   Abbild: postgres:13.2
   neustart: immer
   Umgebung:
     - POSTGRES_USER=admin
     - POSTGRES_PASSWORD=Passwort
     - POSTGRES_DB=Städte
   Ports:
     - "5432:5432"
   Volumes:
     - postgres_data:/data/db

 pgadmin:
   container_name: pgadmin4
   Abbild: dpage/pgadmin4
   Neustart: immer
   Umgebung:
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: passwort
   ports:
     - "15050:80"
   Volumes:
     - pgadmin_data:/data/pgadmin

Volumes:
 postgres_data:
 pgadmin_data:

Aber können Sie das Problem hier erkennen?

Ein Frachtschiff, das alles blockiert

Das obige Beispiel ist sehr einfach. Nur eine Postgres-Datenbank, pgAdmin und das ist alles. Wenn Sie

bash
$ mvn clean verify

dann startet das Maven-Plugin die Container und schaltet sie nach den Tests wieder aus. Die Probleme beginnen, wenn das Projekt wächst und unsere Compose-Datei ebenfalls wächst. Jedes Mal müssen Sie alle Container starten, und sie bleiben während des gesamten Builds aktiv. Sie können die Situation ein wenig verbessern, indem Sie die Konfiguration der Plugin-Ausführung ändern, aber das reicht nicht aus. Im schlimmsten Fall erschöpfen Ihre Container die Systemressourcen, bevor die Tests beginnen!

Und das ist nicht das einzige Problem. Sie können nicht einen einzigen Integrationstest von Ihrer IDE aus durchführen. Vorher müssen Sie die Container von Hand starten. Darüber hinaus wird der nächste Maven-Lauf diese Container abbauen (sehen Sie sich unten Ausführung).

Diese Lösung ist also wie ein großes Frachtschiff. Wenn alles gut funktioniert, dann ist alles in Ordnung. Jedes unerwartete oder ungewöhnliche Verhalten führt zu einer Art Katastrophe.

Testcontainer - Ausführen von Containern aus Tests

Aber was wäre, wenn wir unsere Container von Tests aus starten könnten? Diese Idee sieht gut aus, und sie wird bereits umgesetzt. TestcontainerDa wir gerade über dieses Projekt sprechen, hier eine Lösung für unsere Probleme. Nicht ideal, aber niemand ist perfekt.

Dies ist eine Java Bibliothek, die JUnit- und Spock-Tests unterstützt und eine leichtgewichtige und einfache Möglichkeit bietet, den Docker-Container auszuführen. Werfen wir einen Blick darauf und schreiben wir etwas Code!

Voraussetzungen und Konfiguration

Bevor wir beginnen, müssen wir unsere Konfiguration überprüfen. Test-Container brauchen:

  • Docker in Version v17.09,
  • Java Mindestversion 1.8,
  • Zugang zum Netzwerk, insbesondere zum docker.hub.

Weitere Informationen über die Anforderungen für bestimmte Betriebssysteme und CIs finden Sie unter
in Dokumentation.

Nun ist es an der Zeit, ein paar Zeilen zu pom.xml.

Ich verwende Spring Boot in dem Projekt, um Boilerplate zu reduzieren. Test-Container sind unabhängig vom Spring Framework und können auch ohne dieses verwendet werden.
org.testcontainers
       testcontainers-bom
       ${testcontaines.version}
       pom
       import
     
   
 
 
   
     org.postgresql
     postgresql
     Laufzeit
   
   
     org.testcontainers
     postgresql
     test
   
   
     org.testcontainers
     junit-jupiter
     test

Ich benutze Test-Container Version 1.17.3Sie können aber gerne die neueste Version verwenden.

Tests mit Postgres-Container

Der erste Schritt besteht darin, unsere Instanz eines Containers vorzubereiten. Sie können dies direkt im Test tun, aber eine unabhängige Klasse sieht besser aus.

public class Postgres13TC extends PostgreSQLContainer {

 private static final Postgres13TC TC = new Postgres13TC();

 private Postgres13TC() {
   super("postgres:13.2");
 }

 public static Postgres13TC getInstance() {
   return TC;
 }

 @Override
 public void start() {
   super.start();
   System.setProperty("DB_URL", TC.getJdbcUrl());
   System.setProperty("DB_USERNAME", TC.getUsername());
   System.setProperty("DB_PASSWORD", TC.getPassword());
 }

 @Override
 public void stop() {
   // nichts tun. Dies ist eine gemeinsam genutzte Instanz. Lassen Sie die JVM diese Operation durchführen.
 }
}

Zu Beginn der Tests erstellen wir eine Instanz von Postgres13TC. Diese Klasse kann Informationen über unseren Container verwalten. Das Wichtigste sind hier die Datenbankverbindungszeichenfolgen und die Anmeldeinformationen. Nun ist es an der Zeit, einen sehr einfachen Test zu schreiben.

@Testcontainer
Klasse SimpleDbTest {

 @Container
 private static Postgres13TC = Postgres13TC.getInstance();

 @Test
 void testConnection() {
   assumeThat(postgres13TC.isRunning());
   var connectionProps = new Eigenschaften();
   connectionProps.put("user", postgres13TC.getUsername());
   connectionProps.put("password", postgres13TC.getPassword());

   try (Verbindung = DriverManager.getConnection(postgres13TC.getJdbcUrl(),
       connectionProps)) {
     var resultSet = connection.prepareStatement("Select 1").executeQuery();
     resultSet.next();
     assertThat(resultSet.getInt(1)).isEqualTo(1);
   } catch (SQLException sqlException) {
     assertThat((Exception) sqlException).doesNotThrowAnyException();
   }
 }
}

Ich verwende hier JUnit 5. Anmerkung @Testcontainers ist ein Teil der Erweiterungen, die Container in der Testumgebung kontrollieren. Sie finden alle Felder mit @Container und Start- bzw. Stopp-Container.

Tests mit Spring Boot

Wie ich bereits erwähnt habe, verwende ich Spring Boot in diesem Projekt. In diesem Fall müssen wir ein wenig mehr Code schreiben. Der erste Schritt besteht darin, eine zusätzliche Konfigurationsklasse zu erstellen.

@Slf4j
public class ContainerInit implementiert
   ApplicationContextInitializer {

 public static Postgres13TC;

 static {
   postgres13TC = Postgres13TC.getInstance();
   postgres13TC.start();
 }

 @Override
 public void initialize(ConfigurableApplicationContext applicationContext) {
   TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
       applicationContext,
       "spring.datasource.url=" + postgres13TC.getJdbcUrl(),
       "spring.datasource.username=" + postgres13TC.getUsername(),
       "spring.datasource.password=" + postgres13TC.getPassword(),
       "db.host=" + postgres13TC.getHost(),
       "db.port=" + postgres13TC.getMappedPort(postgres13TC.POSTGRESQL_PORT),
       "db.name=" + postgres13TC.getDatabaseName(),
       "db.username=" + postgres13TC.getUsername(),
       "db.passwort=" + postgres13TC.getPasswort()
   );
 }
}

Diese Klasse überschreibt die vorhandenen Eigenschaften mit Werten aus der Prüfbehälter. Die ersten drei Eigenschaften sind Standard-Spring-Eigenschaften. Die nächsten fünf sind zusätzliche, benutzerdefinierte Eigenschaften, die verwendet werden können, um andere Ressourcen und Erweiterungen wie z.B. liquibase zu konfigurieren:

spring.liquibase.change-log=classpath:/db/changelog/dbchangelog.xml
spring.liquibase.url=jdbc:postgresql://${db.host:localhost}:${db.port:5432}/${db.name:cities}
spring.liquibase.user=${db.username:admin}
spring.liquibase.password=${db.password:password}
spring.liquibase.enabled=true

Nun ist es an der Zeit, einen einfachen Integrationstest zu definieren.

@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@KontextKonfiguration(initializers = ContainerInit.class)
@Testcontainer
Klasse DummyRepositoryTest {

 @Autowired
 private DummyRepository;

 @Test
 void shouldReturnDummy() {
   var byId = dummyRepository.getById(10L);
   var expected = new Dummy();
   expected.setId(10L);
   assertThat(byId).completes().emitsCount(1).emits(expected);
 }
}

Wir haben hier einige zusätzliche Anmerkungen.

  • @SpringBootTest(webUmgebung = RANDOM_PORT) - markiert den Test als Spring Boot-Test und startet den Spring-Kontext.
  • @AutoConfigureTestDatabase(replace = NONE) - Diese Anmerkungen besagen, dass die Spring-Test-Erweiterung die Postgres-Datenbankkonfiguration nicht durch H2 in der Speicherkonfiguration ersetzen soll.
  • @Kontextkonfiguration(initializers = ContainerInit.class) - einen zusätzlichen Frühlingskontext
    Konfiguration, in der wir die Eigenschaften von Test-Container.
  • @Testcontainers - wie bereits erwähnt, steuert dieser Vermerk den Lebenszyklus des Containers.

In diesem Beispiel verwende ich reaktive Repositories, aber es funktioniert genauso mit gängigen JDBC- und JPA-Repositories.

Jetzt können wir diesen Test ausführen. Wenn es der erste Lauf ist, muss die Engine Images von docker.hub ziehen. Das kann einen Moment dauern. Danach werden wir sehen, dass zwei Container gelaufen sind. Einer ist Postgres und der andere ist Testcontainers Controller. Dieser zweite Container verwaltet die laufenden Container, und selbst wenn die JVM unerwartet stoppt, schaltet er die Container ab und räumt die Umgebung auf.

Wir fassen zusammen

Test-Container sind sehr einfach zu bedienende Tools, die uns helfen, Integrationstests zu erstellen, die Docker-Container verwenden. Das gibt uns mehr Flexibilität und erhöht die Entwicklungsgeschwindigkeit. Die ordnungsgemäße Einrichtung der Testkonfiguration verringert den Zeitaufwand für die Einarbeitung neuer Entwickler. Sie müssen nicht alle Abhängigkeiten einrichten, sondern nur die geschriebenen Tests mit ausgewählten Konfigurationsdateien ausführen.

Kooperationsbanner

Ähnliche Artikel

Software-Entwicklung

Zukunftssichere Web-Apps bauen: Einblicke vom The Codest-Expertenteam

Entdecken Sie, wie sich The Codest bei der Erstellung skalierbarer, interaktiver Webanwendungen mit Spitzentechnologien auszeichnet, die nahtlose Benutzererfahrungen auf allen Plattformen bieten. Erfahren Sie, wie unsere Expertise die digitale Transformation und...

DAS SCHÖNSTE
Software-Entwicklung

Top 10 Softwareentwicklungsunternehmen in Lettland

Erfahren Sie in unserem neuesten Artikel mehr über die besten Softwareentwicklungsunternehmen Lettlands und ihre innovativen Lösungen. Entdecken Sie, wie diese Technologieführer Ihr Unternehmen voranbringen können.

thecodest
Enterprise & Scaleups Lösungen

Grundlagen der Java-Softwareentwicklung: Ein Leitfaden für erfolgreiches Outsourcing

Entdecken Sie diesen wichtigen Leitfaden zum erfolgreichen Outsourcing der Java-Softwareentwicklung, um die Effizienz zu steigern, auf Fachwissen zuzugreifen und den Projekterfolg mit The Codest voranzutreiben.

thecodest
Software-Entwicklung

Der ultimative Leitfaden für Outsourcing in Polen

Der Anstieg des Outsourcings in Polen wird durch wirtschaftliche, bildungspolitische und technologische Fortschritte angetrieben, die das IT-Wachstum und ein unternehmensfreundliches Klima fördern.

TheCodest
Enterprise & Scaleups Lösungen

Der vollständige Leitfaden für IT-Audit-Tools und -Techniken

IT-Audits gewährleisten sichere, effiziente und gesetzeskonforme Systeme. Erfahren Sie mehr über ihre Bedeutung, indem Sie den vollständigen Artikel lesen.

Der Codest
Jakub Jakubowicz CTO & Mitbegründer

Abonnieren Sie unsere Wissensdatenbank und bleiben Sie auf dem Laufenden über das Fachwissen aus dem IT-Sektor.

    Über uns

    The Codest - Internationales Software-Unternehmen mit technischen Zentren in Polen.

    Vereinigtes Königreich - Hauptsitz

    • Büro 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokale Tech-Hubs

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polen

      Der Codest

    • Startseite
    • Über uns
    • Dienstleistungen
    • Fallstudien
    • Gewusst wie
    • Karriere
    • Wörterbuch

      Dienstleistungen

    • IT-Beratung
    • Software-Entwicklung
    • Backend-Softwareentwicklung
    • Frontend-Softwareentwicklung
    • Staff Augmentation
    • Backend-Entwickler
    • Cloud-Ingenieure
    • Daten-Ingenieure
    • Andere
    • QS-Ingenieure

      Ressourcen

    • Fakten und Mythen über die Zusammenarbeit mit einem externen Softwareentwicklungspartner
    • Aus den USA nach Europa: Warum entscheiden sich amerikanische Start-ups für eine Verlagerung nach Europa?
    • Tech Offshore Development Hubs im Vergleich: Tech Offshore Europa (Polen), ASEAN (Philippinen), Eurasien (Türkei)
    • Was sind die größten Herausforderungen für CTOs und CIOs?
    • Der Codest
    • Der Codest
    • Der Codest
    • Privacy policy
    • Website terms of use

    Urheberrecht © 2025 von The Codest. Alle Rechte vorbehalten.

    de_DEGerman
    en_USEnglish sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek de_DEGerman