Integrationstests von Rust mit Docker: Fortgeschrittenes Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Integrationstests von Rust mit Docker: Fortgeschrittenes Niveau



Integrationstests sind ein kritisch wichtiger Schritt in der Rust-Entwicklung, insbesondere wenn Ihre Anwendung mit externen Diensten wie Datenbanken, Nachrichtenwarteschlangen oder HTTP-APIs interagiert. Die Verwendung von Docker ermöglicht die Erstellung isolierter, reproduzierbarer Umgebungen für Tests. In diesem Artikel betrachten wir fortgeschrittene Techniken: von der grundlegenden Einrichtung bis zur parallelen Ausführung von Tests mit testcontainers und docker-compose.



Warum Docker für Integrationstests?

Traditionelle Mocks und Stubs spiegeln oft nicht das reale Verhalten von Abhängigkeiten wider. Docker löst dieses Problem:

  • Isolation: Jeder Test wird in einem sauberen Container gestartet.
  • Reproduzierbarkeit: Gleiche Umgebung auf allen Entwicklerrechnern und in CI.
  • Parallelität: Mehrere Testdatenbanken können gleichzeitig ausgeführt werden.


1. Grundlegende Einrichtung: Testen mit PostgreSQL

Beginnen wir einfach: Wir testen eine Funktion, die mit PostgreSQL arbeitet. Wir verwenden die Crate testcontainers – einen Rust-Wrapper zur Verwaltung von Docker-Containern.

Fügen Sie die Abhängigkeiten in Cargo.toml hinzu:

[dev-dependencies]testcontainers = "0.18"tokio = { version = "1", features = ["full"] }sqlx = { version = "0.8", features = ["runtime-tokio", "postgres"] }


Beispiel für einen Test:

use sqlx::PgPool;use testcontainers::clients::Cli;use testcontainers::images::postgres::Postgres;

#[tokio::test]async fn test_database_connection() { let docker = Cli::default(); let postgres_instance = docker.run(Postgres::default()); let connection_string = &format!( "postgres://postgres:postgres@127.0.0.1:{}/postgres", postgres_instance.get_host_port_ipv4(5432) );

let pool = PgPool::connect(connection_string).await.unwrap();

// SQL-Abfrage ausführen let row: (i32,) = sqlx::query_as("SELECT 1 + 1") .fetch_one(&pool) .await .unwrap(); assert_eq!(row.0, 2);}

Wichtig: Der Container wird nach Abschluss des Tests automatisch entfernt (dank der Drop-Implementierung).



2. Fortgeschrittene Konfiguration: Eigenes Image mit Migrationen

Oft müssen Migrationen vorab ausgeführt werden. Erstellen wir ein benutzerdefiniertes Image basierend auf einem Dockerfile:

# Dockerfile.testFROM postgres:16-alpineCOPY migrations/ /docker-entrypoint-initdb.d/


Im Rust-Test verwenden wir Image:

use testcontainers::images::generic::GenericImage;

#[tokio::test]async fn test_with_migrations() { let docker = Cli::default(); let image = GenericImage::new("my-app-test:latest") .with_wait_for(testcontainers::core::WaitFor::message_on_stdout( "database system is ready to accept connections" )); let instance = docker.run(image); // ... instance verwenden}

Zum Erstellen des Images in CI kann docker build -f Dockerfile.test -t my-app-test:latest . verwendet werden.



3. Parallele Ausführung von Tests mit Docker Compose

Wenn Ihr Dienst mehrere Abhängigkeiten benötigt (PostgreSQL + Redis), verwenden Sie docker-compose. Erstellen Sie eine Datei docker-compose.test.yml:

version: '3.8'services:  postgres:    image: postgres:16-alpine    environment:      POSTGRES_PASSWORD: testpass    ports:      - "5432"  redis:    image: redis:7-alpine    ports:      - "6379"


Im Rust-Test starten wir die Compose-Umgebung:

use testcontainers::clients::Cli;use testcontainers::images::compose::Compose;

#[tokio::test]async fn test_with_compose() { let docker = Cli::default(); let compose = Compose::new("docker-compose.test.y

Blogs

Buchempfehlungen