0Pricing
Learn Rust Coding · Lektion

Die API testen

Integrationstests

Die API testen ist eine kostenlose Learn Rust Coding-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Learn Rust Coding-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.

Warum eine API testen?

Tests geben Ihnen die Sicherheit, dass Endpunkte korrekt funktionieren und auch bei Änderungen am Code weiter funktionieren. Für eine REST-API sind Integrationstests am wertvollsten: Sie testen den echten Router von Anfang bis Ende, indem sie Anfragen senden und die Antworten überprüfen.

In dieser Lektion geht es um Unit-Tests, den Tower-oneshot-Trick und vollständige Integrationstests.

Unit-Tests für reine Logik

Logik, die das Netzwerk nicht verwendet, etwa Validierung, kann mit einfachen Rust-Unit-Tests getestet werden. Legen Sie diese in einem #[cfg(test)]-Modul neben dem Code ab. Sie laufen mit cargo test schnell durch.

fn validate_title(title: &str) -> bool {
    !title.trim().is_empty()
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn rejects_empty() {
        assert!(!validate_title("   "));
        assert!(validate_title("buy milk"));
    }
}

Asynchrone Tests

Handler sind asynchron. Daher müssen Testfunktionen, die await verwenden, in einer Runtime ausgeführt werden. Verwenden Sie #[tokio::test] statt #[test]. Dadurch wird für diesen Test eine Tokio-Runtime gestartet, sodass Sie asynchronen Code mit .await aufrufen können.

async fn add(a: i32, b: i32) -> i32 { a + b }

#[cfg(test)]
mod tests {
    use super::*;
    #[tokio::test]
    async fn adds() {
        assert_eq!(add(2, 3).await, 5);
    }
}

Testen ohne Netzwerk

Axum-Router implementieren das Tower-Service-Trait. Daher können Sie ihnen Anfragen direkt übergeben, ohne einen Port zu binden. Die Methode oneshot nimmt eine einzelne Request entgegen und gibt die Response zurück. Dadurch werden Integrationstests schnell und deterministisch.

// dev-dependencies needed: tower (for ServiceExt), http-body-util
use axum::{Router, routing::get};
use axum::http::{Request, StatusCode};
use axum::body::Body;
use tower::ServiceExt; // brings in oneshot

async fn check() {
    let app = Router::new().route("/health", get(|| async { "ok" }));
    let res = app
        .oneshot(Request::builder().uri("/health").body(Body::empty()).unwrap())
        .await.unwrap();
    assert_eq!(res.status(), StatusCode::OK);
}

Den Statuscode überprüfen

Das Erste, was die meisten Tests überprüfen, ist der HTTP-Status. Eine fehlende Ressource sollte 404 liefern, eine erfolgreiche Erstellung 201 und ein fehlerhafter Body 400. Erstellen Sie eine Anfrage für die Route und vergleichen Sie res.status() mit dem erwarteten Code.

use axum::http::{Request, StatusCode};
use axum::body::Body;
use tower::ServiceExt;

async fn missing_returns_404(app: axum::Router) {
    let res = app
        .oneshot(Request::builder()
            .uri("/todos/999")
            .body(Body::empty()).unwrap())
        .await.unwrap();
    assert_eq!(res.status(), StatusCode::NOT_FOUND);
}

Den Response-Body lesen

Um JSON zu überprüfen, sammeln Sie den Response-Body als Bytes und deserialisieren Sie ihn. Der Helfer http_body_util::BodyExt::collect sammelt den Body, anschließend analysiert serde_json ihn in Ihr Modell, sodass Sie einzelne Felder überprüfen können.

use http_body_util::BodyExt;

async fn read_json(res: axum::http::Response<axum::body::Body>) {
    let bytes = res.into_body().collect().await.unwrap().to_bytes();
    let todo: serde_json::Value = serde_json::from_slice(&bytes).unwrap();
    assert_eq!(todo["done"], false);
}

Einen JSON-Body senden

Um einen POST zu testen, erstellen Sie eine Anfrage mit einem JSON-Body und dem richtigen Content-Type-Header. Serialisieren Sie Ihre Eingabestruktur, setzen Sie content-type: application/json und leiten Sie die Anfrage durch oneshot.

use axum::http::{Request, StatusCode, header};
use axum::body::Body;
use tower::ServiceExt;

async fn create_returns_201(app: axum::Router) {
    let body = serde_json::json!({ "title": "test" }).to_string();
    let res = app
        .oneshot(Request::builder()
            .method("POST").uri("/todos")
            .header(header::CONTENT_TYPE, "application/json")
            .body(Body::from(body)).unwrap())
        .await.unwrap();
    assert_eq!(res.status(), StatusCode::CREATED);
}

Ein wiederverwendbarer Test-App-Builder

Jeder Test sollte mit einem sauberen Zustand beginnen. Schreiben Sie einen Helfer, der einen neuen Router mit einer neuen In-Memory- oder Testdatenbank erstellt. Wenn Sie ihn in jedem Test aufrufen, sind die Tests voneinander isoliert, sodass ein Test keinen anderen beeinflussen kann.

use axum::Router;
use std::sync::{Arc, Mutex};

fn test_app() -> Router {
    let store = Arc::new(Mutex::new(Vec::new()));
    build(store) // same build() the real server uses
}

Das tests-Verzeichnis

Integrationstests befinden sich in einem tests/-Ordner auf oberster Ebene. Jede dort enthaltene Datei wird als eigene Crate kompiliert, die die öffentliche API Ihrer Bibliothek verwendet. Dadurch müssen Sie über dieselbe Schnittstelle testen, die auch echte Benutzer sehen.

  • tests/api.rs enthält Ihre Endpunkttests.
  • Führen Sie alle Tests mit cargo test aus.
// tests/api.rs
use my_api::build_router; // exported from lib.rs

#[tokio::test]
async fn health_ok() {
    let _app = build_router();
    // send a request and assert ...
}

Mit einer Datenbank testen

Wenn Handler sqlx verwenden, benötigen auch die Tests eine Datenbank. Übliche Strategien sind eine eigene Testdatenbank, Transaktionen, die nach jedem Test zurückgerollt werden, oder das Makro #[sqlx::test] von sqlx, das automatisch pro Test eine saubere Datenbank bereitstellt.

// requires sqlx test features and a DATABASE_URL
use sqlx::PgPool;

#[sqlx::test]
async fn inserts_todo(pool: PgPool) {
    let todo = create(&pool, "learn rust").await.unwrap();
    assert_eq!(todo.title, "learn rust");
    assert_eq!(todo.done, false);
}

Was Sie testen sollten

Streben Sie eine ausgewogene Testsuite an:

  • Erfolgsfälle: Gültige Anfragen liefern den richtigen Status und Body.
  • Fehler: Fehlende Ressourcen liefern 404, fehlerhafte Eingaben 400.
  • Sonderfälle: Leere Listen, Grenzwerte und Duplikate.

Führen Sie cargo test in CI aus, damit Regressionen vor dem Deployment erkannt werden.

Kurzer Check

Testen Sie Ihr Verständnis vom Testen einer API.

Zusammenfassung

Sie haben gelernt, eine Rust-REST-API zu testen:

  • Testen Sie reine Logik mit Unit-Tests; verwenden Sie #[tokio::test] für asynchronen Code.
  • oneshot führt den Router direkt aus, ohne dass ein Port benötigt wird.
  • Erstellen Sie Anfragen mit Bodies und Headern; sammeln und analysieren Sie Response-Bodies.
  • Verwenden Sie pro Test einen neuen App-Builder zur Isolation; legen Sie Integrationstests in tests/ ab.
  • #[sqlx::test] stellt saubere Datenbanken bereit; decken Sie Erfolgsfälle, Fehler und Sonderfälle ab.

Häufig gestellte Fragen

Ist die Lektion „Die API testen“ kostenlos?

Ja — der vollständige Text von „Die API testen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Learn Rust Coding-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Die API testen“?

Integrationstests Du übst Learn Rust Coding mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Learn Rust Coding zu starten?

Keine Vorkenntnisse erforderlich. Learn Rust Coding auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Die API testen“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Learn Rust Coding-Lektion Code schreiben und ausführen?

Ja. Jede Learn Rust Coding-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Projekteinrichtung
  2. Endpoints und Modelle
  3. Datenbankintegration
  4. Die API testen
← Zurück zu Learn Rust Coding