1. Einleitung
In diesem Tutorial sehen wir uns die Java TestContainers- Bibliothek an. Es ermöglicht uns, Docker-Container in unseren Tests zu verwenden. Infolgedessen können wir in sich geschlossene Integrationstests schreiben, die von externen Ressourcen abhängen.
Wir können jede Ressource in unseren Tests verwenden, die ein Docker-Image haben. Beispielsweise gibt es Bilder für Datenbanken, Webbrowser, Webserver und Nachrichtenwarteschlangen. Daher können wir sie in unseren Tests als Container ausführen.
2. Anforderungen
Die TestContainers- Bibliothek kann mit Java 8 und höher verwendet werden. Außerdem ist es mit der JUnit Rules API kompatibel.
Definieren wir zunächst die Maven-Abhängigkeit für die Kernfunktionalität:
org.testcontainers testcontainers 1.11.4
Es gibt auch Module für Spezialcontainer. In diesem Tutorial verwenden wir PostgreSQL und Selenium.
Fügen wir die relevanten Abhängigkeiten hinzu:
org.testcontainers postgresql 1.11.4 org.testcontainers selenium 1.11.4
Wir können die neuesten Versionen auf Maven Central finden.
Außerdem benötigen wir Docker, um Container auszuführen . Installationsanweisungen finden Sie in der Docker-Dokumentation.
Stellen Sie sicher, dass Sie Docker-Container in Ihrer Testumgebung ausführen können.
3. Verwendung
Konfigurieren wir eine generische Containerregel:
@ClassRule public static GenericContainer simpleWebServer = new GenericContainer("alpine:3.2") .withExposedPorts(80) .withCommand("/bin/sh", "-c", "while true; do echo " + "\"HTTP/1.1 200 OK\n\nHello World!\" | nc -l -p 80; done");
Wir erstellen eine GenericContainer-Testregel , indem wir einen Docker-Image-Namen angeben . Dann konfigurieren wir es mit Builder-Methoden:
- Wir verwenden withExposedPorts , um einen Port aus dem Container verfügbar zu machen
- withCommand definiert einen Containerbefehl. Es wird ausgeführt, wenn der Container startet.
Die Regel wird mit @ClassRule kommentiert . Infolgedessen wird der Docker-Container gestartet, bevor ein Test in dieser Klasse ausgeführt wird . Der Container wird zerstört, nachdem alle Methoden ausgeführt wurden.
Wenn Sie die Annotation @Rule anwenden, startet die GenericContainer- Regel für jede Testmethode einen neuen Container. Und es stoppt den Container, wenn diese Testmethode abgeschlossen ist.
Wir können IP-Adresse und Port verwenden, um mit dem im Container ausgeführten Prozess zu kommunizieren :
@Test public void givenSimpleWebServerContainer_whenGetReuqest_thenReturnsResponse() throws Exception { String address = "//" + simpleWebServer.getContainerIpAddress() + ":" + simpleWebServer.getMappedPort(80); String response = simpleGetRequest(address); assertEquals(response, "Hello World!"); }
4. Nutzungsmodi
Es gibt verschiedene Verwendungsmodi der Testcontainer. Wir haben ein Beispiel für die Ausführung eines GenericContainer gesehen.
Die TestContainers- Bibliothek verfügt auch über Regeldefinitionen mit speziellen Funktionen. Sie sind für Container gängiger Datenbanken wie MySQL, PostgreSQL; und andere mögen Web-Clients.
Obwohl wir sie als generische Container ausführen können, bieten die Spezialisierungen erweiterte Komfortmethoden.
4.1. Datenbanken
Nehmen wir an, wir benötigen einen Datenbankserver für Integrationstests auf Datenzugriffsebene. Mit Hilfe der TestContainers-Bibliothek können wir Datenbanken in Containern ausführen.
Zum Beispiel starten wir einen PostgreSQL-Container mit der PostgreSQLContainer- Regel. Dann können wir Hilfsmethoden verwenden. Dies sind getJdbcUrl, getUsername, getPassword für die Datenbankverbindung:
@Rule public PostgreSQLContainer postgresContainer = new PostgreSQLContainer(); @Test public void whenSelectQueryExecuted_thenResulstsReturned() throws Exception { String jdbcUrl = postgresContainer.getJdbcUrl(); String username = postgresContainer.getUsername(); String password = postgresContainer.getPassword(); Connection conn = DriverManager .getConnection(jdbcUrl, username, password); ResultSet resultSet = conn.createStatement().executeQuery("SELECT 1"); resultSet.next(); int result = resultSet.getInt(1); assertEquals(1, result); }
Es ist auch möglich, PostgreSQL als generischen Container auszuführen. Es wäre jedoch schwieriger, die Verbindung zu konfigurieren.
4.2. Web-Treiber
Ein weiteres nützliches Szenario ist das Ausführen von Containern mit Webbrowsern. Die BrowserWebDriverContainer- Regel ermöglicht das Ausführen von Chrome und Firefox in Docker-Selen- Containern. Dann verwalten wir sie mit RemoteWebDriver.
Dies ist sehr nützlich für die Automatisierung von UI- / Abnahmetests für Webanwendungen:
@Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withCapabilities(new ChromeOptions()); @Test public void whenNavigatedToPage_thenHeadingIsInThePage() { RemoteWebDriver driver = chrome.getWebDriver(); driver.get("//example.com"); String heading = driver.findElement(By.xpath("/html/body/div/h1")) .getText(); assertEquals("Example Domain", heading); }
4.3. Docker Compose
Wenn die Tests komplexere Dienste erfordern, können wir sie in einer Docker-Compose- Datei angeben :
simpleWebServer: image: alpine:3.2 command: ["/bin/sh", "-c", "while true; do echo 'HTTP/1.1 200 OK\n\nHello World!' | nc -l -p 80; done"]
Dann verwenden wir die DockerComposeContainer- Regel. Diese Regel startet und führt Dienste aus, wie in der Erstellungsdatei definiert.
Wir verwenden die Methoden getServiceHost und getServicePost , um die Verbindungsadresse zum Dienst zu erstellen:
@ClassRule public static DockerComposeContainer compose = new DockerComposeContainer( new File("src/test/resources/test-compose.yml")) .withExposedService("simpleWebServer_1", 80); @Test public void givenSimpleWebServerContainer_whenGetReuqest_thenReturnsResponse() throws Exception { String address = "//" + compose.getServiceHost("simpleWebServer_1", 80) + ":" + compose.getServicePort("simpleWebServer_1", 80); String response = simpleGetRequest(address); assertEquals(response, "Hello World"); }
5. Schlussfolgerung
Wir haben gesehen, wie wir die TestContainers- Bibliothek verwenden können. Es erleichtert die Entwicklung und Ausführung von Integrationstests.
Wir haben die GenericContainer- Regel für Container mit bestimmten Docker-Bildern verwendet. Dann haben wir uns die Regeln für PostgreSQLContainer, BrowserWebDriverContainer und DockerComposeContainer angesehen . Sie bieten mehr Funktionen für bestimmte Anwendungsfälle.
Schließlich finden Sie Codebeispiele hier auf GitHub.