Testen in Rust: Unit, Integration, E2E von A bis Z

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

Einleitung: Warum Tests in Rust die Grundlage für zuverlässigen Code sind



Rust ist eine Systemprogrammiersprache, die für ihre Speichersicherheit und Leistung bekannt ist. Allerdings garantiert selbst der strengste Compiler nicht, dass Ihr Programm genau das tut, was benötigt wird. Hier kommen Tests ins Spiel. In Rust gehört die integrierte Testunterstützung zu den besten moderner Sprachen. Sie können Unit-Tests, Integrationstests und E2E-Tests (End-to-End) schreiben, ohne auf Drittanbieter-Bibliotheken angewiesen zu sein.



In diesem Artikel werden wir alle drei Testebenen mit praktischen Beispielen durchgehen. Sie lernen, wie Sie Tests schreiben, wie Sie sie mit cargo test ausführen und wie Sie die Testinfrastruktur für große Projekte organisieren.



1. Unit-Tests in Rust: Testen von Funktionen und Modulen



Unit-Tests überprüfen die Funktionsweise einzelner Funktionen oder Methoden isoliert. In Rust ist es üblich, Unit-Tests direkt in der Quellcodedatei zu platzieren, innerhalb eines tests-Moduls mit dem #[cfg(test)]-Attribut. Dadurch können Tests auf private Funktionen des Moduls zugreifen.



1.1. Ihr erster Unit-Test



Lassen Sie uns eine einfache Rechenbibliothek erstellen und Tests dafür schreiben.



// src/lib.rspub fn add(a: i32, b: i32) -> i32 {    a + b}

pub fn divide(a: f64, b: f64) -> Result<f64, String> { if b == 0.0 { Err(String::from("Division durch Null")) } else { Ok(a / b) }}

#[cfg(test)]mod tests { use super::*;

#[test] fn test_add() { assert_eq!(add(2, 3), 5); }

#[test] fn test_divide_success() { let result = divide(10.0, 2.0).unwrap(); assert_eq!(result, 5.0); }

#[test] fn test_divide_by_zero() { let result = divide(10.0, 0.0); assert!(result.is_err()); assert_eq!(result.unwrap_err(), "Division durch Null"); }}


Führen Sie die Tests mit dem Befehl cargo test aus. Sie sehen grüne Häkchen, wenn alle Tests bestanden werden.



1.2. Test-Attribute



  • #[test] — kennzeichnet die Funktion als Test.
  • #[should_panic] — der Test gilt als bestanden, wenn die Funktion eine Panik auslöst.
  • #[ignore] — deaktiviert den Test vorübergehend.


#[test]#[should_panic(expected = "Paniknachricht")]fn test_panic() {    panic!("Paniknachricht");}

#[test]#[ignore = "Test deaktiviert, bis Bug #42 behoben ist"]fn test_expensive() { // Langlaufender Test}


2. Integrationstests: Überprüfung der Komponenteninteraktion



Integrationstests überprüfen das Zusammenspiel mehrerer Module oder externer Abhängigkeiten. In Rust werden sie in einem separaten tests/-Verzeichnis auf Projektebene platziert. Jede Datei in diesem Ordner ist eine eigene Test-Crate, die nur die öffentliche API Ihrer Bibliothek sieht.



2.1. Struktur von Integrationstests



Erstellen Sie einen tests/-Ordner und eine Datei tests/integration_test.rs:



// tests/integration_test.rsuse my_crate::add; // Name Ihrer Crate

#[test]fn test_add_integration() { // Überprüfen, dass die Funktion als Teil der Bibliothek funktioniert let result = add(10, 20); assert_eq!(result, 30);}

#[test]fn test_divide_integration() { // Test mit mehreren Aufrufen let a = 100.0; let b = 4.0; let result = my_crate::divide(a, b).unwrap(); assert!(result > 0.0); assert_eq!(result, 25.0);}


2.2. Gemeinsame Module für Integrationstests



Wenn Sie Code zwischen Integrationstests wiederverwenden müssen, erstellen Sie eine Datei tests/common/mod.rs. Diese wird nicht als Testdatei behandelt, kann aber von anderen Tests importiert werden.



// tests/common/mod.rspub fn setu                

Blogs

Buchempfehlungen