Testen in Rust: Frameworks und Werkzeuge
Rust ist eine systemnahe Programmiersprache, die großen Wert auf Zuverlässigkeit und Sicherheit legt. Das integrierte Testsystem ist eine der wichtigsten Funktionen, die es ermöglicht, qualitativ hochwertigen Code zu schreiben, ohne zusätzliche Frameworks installieren zu müssen. In diesem Artikel betrachten wir die wichtigsten Werkzeuge zum Testen in Rust im Detail: von einfachen Unit-Tests bis hin zu komplexen property-basierten Tests und Benchmarks.
Integriertes Test-Framework
In Rust werden Tests mit dem Befehl cargo test ausgeführt. Tests sind normale Funktionen, die mit dem Attribut #[test] markiert sind. Das Framework sammelt automatisch alle solche Funktionen in Ihrem Projekt und führt sie aus.
Unit-Tests
Unit-Tests befinden sich normalerweise in derselben Datei wie der zu testende Code, in einem separaten Modul tests. Dies ermöglicht das Testen privater Funktionen.
// src/lib.rspub fn add(a: i32, b: i32) -> i32 { a + b}
fn private_helper(x: i32) -> i32 { x * 2}
#[cfg(test)]mod tests { use super::*;
#[test] fn test_add() { assert_eq!(add(2, 3), 5); }
#[test] fn test_private_helper() { assert_eq!(private_helper(5), 10); }}Ausführung: cargo test
Integrationstests
Integrationstests befinden sich im Verzeichnis tests/ auf der Wurzelebene des Projekts. Jede Datei in diesem Ordner ist ein separater Crate, der Ihre öffentliche API testet.
// tests/integration_test.rsuse my_crate::add;
#[test]fn test_add_integration() { assert_eq!(add(10, 20), 30);}Makros für Überprüfungen
Rust bietet mehrere eingebaute Makros zum Schreiben von Überprüfungen:
assert!(expression)— bricht ab, wenn der Ausdruck falsch ist.assert_eq!(left, right)— prüft Gleichheit mitPartialEq.assert_ne!(left, right)— prüft Ungleichheit.debug_assert!()— funktioniert nur in Debug-Builds.
#[test]fn test_with_assert() { let result = some_function(); assert!(result.is_ok(), "Ok erwartet, erhalten: {:?}", result); assert_eq!(result.unwrap(), 42);}Doctests
Eine der leistungsstärksten Funktionen von Rust ist die Möglichkeit, Tests direkt in der Dokumentation zu schreiben. Code innerhalb von ///- oder //!-Blöcken wird automatisch kompiliert und als Test ausgeführt.
/// Addiert zwei Zahlen.////// # Beispiele////// ```/// use my_crate::add;/// assert_eq!(add(1, 2), 3);/// ```pub fn add(a: i32, b: i32) -> i32 { a + b}Ausführung: cargo test — Doctests werden zusammen mit normalen Tests ausgeführt.
Property-basiertes Testen mit proptest
Die Bibliothek proptest (Analogon zu Hypothesis in Python oder QuickCheck in Haskell) ermöglicht die Generierung zufälliger Eingabedaten und die Überprüfung von Invarianten.
use proptest::prelude::*;
fn reverse_string(s: &str) -> String { s.chars().rev().collect()}
proptest! { #[test] fn test_reverse_twice(s in ".*") { let reversed = reverse_string(&s); let double_reversed = reverse_string(&reversed); assert_eq!(s, double_reversed); }}Installation: cargo add proptest
Benchmarks
Zur Messung der Leistung gibt es in Rust stabile Benchmarks (ab Rust 1.78) über cargo bench und die Crate criterion für komplexere Szenarien.
Integrierte Benchmarks (nightly)
#![feature(test)]extern crate test;
#[bench]fn bench_add(b: &mut test::Bencher) { b.iter(|| add(1, 2));}Benchmarks mit criterion
Auch in der Bibliothek
Empfehlungen