¡Bienvenidos de nuevo a Rustaceo.es! En las entregas anteriores, construimos nuestra API REST en Rust con Actix-Web y agregamos persistencia con SQLx. Ahora, nos enfocaremos en una parte crucial del desarrollo: escribir tests automatizados para asegurar el correcto funcionamiento de nuestra API.
🚀 Objetivos de esta parte #
- Escribir tests unitarios y de integración para los endpoints.
- Simular peticiones HTTP con
actix-web::test
. - Validar la correcta interacción con la base de datos.
🛠 Configuración de los tests #
Para probar nuestra API, utilizaremos actix-web::test. Ya tenemos Actix-Web en Cargo.toml
, pero asegurémonos de incluir SQLx con un entorno de prueba:
[dev-dependencies]
actix-rt = "2"
sqlx = { version = "0.6", features = ["postgres", "runtime-tokio-native-tls"] }
serde_json = "1"
reqwest = { version = "0.11", features = ["json"] }
🔍 Escribiendo tests unitarios #
Los tests unitarios verifican el comportamiento de funciones individuales sin depender de la base de datos ni de la API completa.
📌 1️⃣ Testeando la función de bienvenida #
#[Cfg(test)]
mod tests {
use super::*;
use actix_web::{test, App};
#[actix_web::test]
async fn test_bienvenida() {
let app = test::init_service(App::new().route("/", web::get().to(bienvenida))).await;
let req = test::TestRequest::get().uri("/").to_request();
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success());
}
}
✔ test::init_service()
inicializa la aplicación para pruebas. ✔ test::TestRequest::get().uri()
simula una petición HTTP GET. ✔ assert!(resp.status().is_success())
valida que la respuesta sea exitosa.
🔄 Escribiendo tests de integración #
Los tests de integración verifican cómo interactúan las partes del sistema, incluyendo la base de datos.
📌 2️⃣ Testeando la creación de un pokémon #
#[Actix_web::test]
async fn test_agregar_elemento() {
let pool = establecer_conexion_test().await;
let app = test::init_service(
App::new()
.app_data(web::Data::new(pool.clone()))
.route("/elementoes", web::post().to(agregar_elemento)),
)
.await;
let nuevo_elemento = json!({"nombre": "Item3", "tipo": "Agua"});
let req = test::TestRequest::post()
.uri("/elementoes")
.set_json(&nuevo_elemento)
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), 201);
}
✔ test::set_json()
envía JSON en la solicitud. ✔ assert_eq!(resp.status(), 201);
verifica que el código de estado sea 201 Created
.
📌 3️⃣ Testeando la consulta de pokémon #
#[Actix_web::test]
async fn test_listar_elemento() {
let pool = establecer_conexion_test().await;
let app = test::init_service(
App::new()
.app_data(web::Data::new(pool.clone()))
.route("/elementoes", web::get().to(listar_elemento)),
)
.await;
let req = test::TestRequest::get().uri("/elementoes").to_request();
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success());
}
✔ Simula una petición GET a /elementoes
para verificar la consulta.
📦 Configurando una base de datos de prueba #
Para evitar modificar datos reales, creamos una base de datos de prueba.
📌 1️⃣ Definir una Conexión de Prueba
use sqlx::PgPool;
use std::env;
async fn establecer_conexion_test() -> PgPool {
dotenv::dotenv().ok();
let database_url = env::var("DATABASE_URL_TEST").expect("DATABASE_URL_TEST no está configurado");
PgPool::connect(&database_url).await.expect("No se pudo conectar a la BD de prueba")
}
📌 2️⃣ Crear la Base de Datos de Prueba
CREATE DATABASE pokedex_test;
Añadimos DATABASE_URL_TEST
en .env.test
:
DATABASE_URL_TEST=postgres://rustaceo:password@localhost/pokedex_test
🏆 Conclusión #
Hemos añadido una capa de pruebas automatizadas a nuestra API REST en Rust.
🎯 Resumen de lo aprendido: ✔ Configuración de tests unitarios y de integración. ✔ Simulación de peticiones HTTP con actix-web::test
. ✔ Validación de la persistencia con una base de datos de prueba.
🔮 Próximo paso: Ampliar la API con autenticación y control de acceso.
¡Nos vemos en la siguiente entrega, Rustaceos!