0Pricing
Learn Rust Coding · Lección

Pruebas de la API

Pruebas de integración

Pruebas de la API es una lección gratuita de Learn Rust Coding en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Learn Rust Coding, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Learn Rust Coding incluye 4 lecciones en total.

¿Por qué probar una API?

Las pruebas le dan la confianza de que los endpoints funcionan correctamente y siguen haciéndolo cuando modifica el código. En una API REST, las pruebas más valiosas son las pruebas de integración: ejercitan el enrutador real de extremo a extremo, envían solicitudes y comprueban las respuestas.

Esta lección abarca las pruebas unitarias, el truco oneshot de Tower y las pruebas de integración completas.

Pruebas unitarias para lógica pura

La lógica que no interactúa con la red, como la validación, puede probarse con pruebas unitarias normales de Rust. Colóquelas en un módulo #[cfg(test)] junto al código. Se ejecutan rápidamente con cargo test.

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"));
    }
}

Pruebas asíncronas

Los controladores son asíncronos, por lo que las funciones de prueba que esperan resultados deben ejecutarse en un runtime. Use #[tokio::test] en lugar de #[test]. Esto inicia un runtime de Tokio para esa prueba y le permite llamar a código asíncrono con .await.

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);
    }
}

Probar sin red

Los enrutadores de Axum implementan el trait Service de Tower, por lo que puede proporcionarles solicitudes directamente sin asociar un puerto. El método oneshot recibe una única Request y devuelve la Response. Esto hace que las pruebas de integración sean rápidas y deterministas.

// 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);
}

Comprobar el código de estado

Lo primero que comprueban la mayoría de las pruebas es el estado HTTP. Un recurso inexistente debería devolver 404, una creación correcta 201 y un cuerpo incorrecto 400. Cree una solicitud para la ruta y compare res.status() con el código esperado.

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);
}

Leer el cuerpo de la respuesta

Para comprobar el JSON, recopile el cuerpo de la respuesta en bytes y deserialícelo. El ayudante http_body_util::BodyExt::collect recopila el cuerpo y, después, serde_json lo analiza en su modelo para permitir comprobaciones a nivel de campo.

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);
}

Enviar un cuerpo JSON

Para probar un POST, cree una solicitud con un cuerpo JSON y el encabezado de tipo de contenido correcto. Serialice su estructura de entrada, establezca content-type: application/json y pásela mediante 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);
}

Un creador de aplicaciones de prueba reutilizable

Cada prueba debería comenzar con un estado limpio. Escriba un ayudante que cree un enrutador nuevo con una base de datos nueva en memoria o de prueba. Llámelo en cada prueba para aislarlas y evitar que una afecte a otra.

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
}

El directorio tests

Las pruebas de integración se encuentran en una carpeta tests/ de nivel superior. Cada archivo incluido allí se compila como un crate independiente que utiliza la API pública de su biblioteca. Esto le obliga a probar mediante la misma interfaz que ven los usuarios reales.

  • tests/api.rs contiene las pruebas de sus endpoints.
  • Ejecútelas todas con cargo test.
// 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 ...
}

Probar con una base de datos

Cuando los controladores usan sqlx, las pruebas también necesitan una base de datos. Algunas estrategias habituales son: una base de datos de prueba dedicada, transacciones que se revierten después de cada prueba o la macro #[sqlx::test] de sqlx, que aprovisiona automáticamente una base de datos limpia para cada prueba.

// 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);
}

Qué probar

Procure tener un conjunto equilibrado:

  • Ruta correcta: las solicitudes válidas devuelven el estado y el cuerpo adecuados.
  • Errores: los recursos inexistentes devuelven 404 y las entradas incorrectas devuelven 400.
  • Casos límite: listas vacías, valores límite y duplicados.

Ejecute cargo test en CI para detectar las regresiones antes del despliegue.

Comprobación rápida

Compruebe cuánto entiende sobre las pruebas de la API.

Resumen

Ha aprendido a probar una API REST de Rust:

  • Pruebe unitariamente la lógica pura; use #[tokio::test] para el código asíncrono.
  • oneshot ejecuta el enrutador directamente, sin necesidad de un puerto.
  • Cree solicitudes con cuerpos y encabezados; recopile y analice los cuerpos de las respuestas.
  • Use un creador de aplicaciones nuevo en cada prueba para aislarlas; coloque las pruebas de integración en tests/.
  • #[sqlx::test] aprovisiona bases de datos limpias; cubra las rutas correctas, los errores y los casos límite.

Preguntas frecuentes

¿La lección «Pruebas de la API» es gratis?

Sí — el texto completo de «Pruebas de la API» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Learn Rust Coding, actualiza a CoddyKit PRO. El curso de Learn Rust Coding incluye 4 lecciones en total.

¿Qué aprenderé en «Pruebas de la API»?

Pruebas de integración Practicas Learn Rust Coding con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Learn Rust Coding?

No se requiere experiencia previa. Learn Rust Coding en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Pruebas de la API»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Learn Rust Coding?

Sí. Cada lección de Learn Rust Coding incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Configuración del proyecto
  2. Endpoints y modelos
  3. Integración con la base de datos
  4. Pruebas de la API
← Volver a Learn Rust Coding