测试 #

测试是保证应用质量的重要手段。本节将介绍如何测试Rocket应用。

单元测试 #

测试模块 #

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

    #[test]
    fn test_hash_password() {
        let password = "test123";
        let hash = hash_password(password).unwrap();
        assert!(verify_password(password, &hash));
    }
    
    #[test]
    fn test_invalid_password() {
        let hash = hash_password("correct").unwrap();
        assert!(!verify_password("wrong", &hash));
    }
}

运行测试 #

bash
cargo test

集成测试 #

测试目录结构 #

text
tests/
├── common/
│   ├── mod.rs
│   └── fixtures.rs
├── user_test.rs
└── auth_test.rs

测试客户端 #

rust
use rocket::local::asynchronous::Client;
use rocket::local::blocking::Client as BlockingClient;

#[rocket::async_test]
async fn test_get_user() {
    let client = Client::tracked(rocket())
        .await
        .expect("valid rocket instance");
    
    let response = client.get("/api/users/1")
        .dispatch()
        .await;
    
    assert_eq!(response.status(), rocket::http::Status::Ok);
}

阻塞客户端测试 #

rust
use rocket::local::blocking::Client;

#[test]
fn test_index() {
    let client = Client::tracked(rocket()).expect("valid rocket instance");
    let response = client.get("/").dispatch();
    
    assert_eq!(response.status(), rocket::http::Status::Ok);
    assert!(response.into_string().unwrap().contains("Hello"));
}

API测试 #

测试JSON响应 #

rust
use rocket::local::blocking::Client;
use rocket::serde::json::serde_json;

#[test]
fn test_json_response() {
    let client = Client::tracked(rocket()).unwrap();
    let response = client.get("/api/users/1").dispatch();
    
    assert_eq!(response.status(), rocket::http::Status::Ok);
    
    let body = response.into_string().unwrap();
    let user: User = serde_json::from_str(&body).unwrap();
    assert_eq!(user.id, 1);
}

测试POST请求 #

rust
#[test]
fn test_create_user() {
    let client = Client::tracked(rocket()).unwrap();
    
    let new_user = NewUser {
        username: "test".to_string(),
        email: "test@example.com".to_string(),
    };
    
    let response = client.post("/api/users")
        .header(rocket::http::ContentType::JSON)
        .body(serde_json::to_string(&new_user).unwrap())
        .dispatch();
    
    assert_eq!(response.status(), rocket::http::Status::Created);
}

测试认证 #

rust
#[test]
fn test_protected_route() {
    let client = Client::tracked(rocket()).unwrap();
    
    let response = client.get("/api/profile")
        .header(rocket::http::Header::new("Authorization", "Bearer invalid-token"))
        .dispatch();
    
    assert_eq!(response.status(), rocket::http::Status::Unauthorized);
    
    let response = client.get("/api/profile")
        .header(rocket::http::Header::new("Authorization", "Bearer valid-token"))
        .dispatch();
    
    assert_eq!(response.status(), rocket::http::Status::Ok);
}

测试工具函数 #

创建测试Rocket实例 #

rust
fn test_rocket() -> Rocket<rocket::Build> {
    rocket::build()
        .manage(create_test_db())
        .mount("/api", routes![get_user, create_user])
}

fn create_test_db() -> Db {
    Db::new()
}

测试夹具 #

rust
mod fixtures {
    use super::*;
    
    pub fn create_test_user(db: &Db) -> User {
        db.create_user(NewUser {
            username: "test".to_string(),
            email: "test@example.com".to_string(),
        })
    }
}

#[test]
fn test_with_fixture() {
    let db = create_test_db();
    let user = fixtures::create_test_user(&db);
    
    assert_eq!(user.username, "test");
}

完整测试示例 #

rust
#[macro_use] extern crate rocket;

use rocket::local::blocking::Client;
use rocket::serde::json::Json;
use rocket::serde::{Serialize, Deserialize};
use std::sync::Mutex;
use std::collections::HashMap;
use rocket::State;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: u32,
    name: String,
}

struct Db {
    users: Mutex<HashMap<u32, User>>,
}

impl Db {
    fn new() -> Self {
        Self {
            users: Mutex::new(HashMap::new()),
        }
    }
    
    fn get(&self, id: u32) -> Option<User> {
        self.users.lock().unwrap().get(&id).cloned()
    }
    
    fn create(&self, name: String) -> User {
        let mut users = self.users.lock().unwrap();
        let id = users.len() as u32 + 1;
        let user = User { id, name };
        users.insert(id, user.clone());
        user
    }
}

#[get("/users/<id>")]
fn get_user(id: u32, db: &State<Db>) -> Option<Json<User>> {
    db.get(id).map(Json)
}

#[post("/users", format = "json", data = "<user>")]
fn create_user(user: Json<serde_json::Value>, db: &State<Db>) -> Json<User> {
    let name = user["name"].as_str().unwrap_or("Unknown").to_string();
    Json(db.create(name))
}

fn test_rocket() -> rocket::Rocket<rocket::Build> {
    rocket::build()
        .manage(Db::new())
        .mount("/api", routes![get_user, create_user])
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_get_nonexistent_user() {
        let client = Client::tracked(test_rocket()).unwrap();
        let response = client.get("/api/users/999").dispatch();
        assert_eq!(response.status(), rocket::http::Status::NotFound);
    }
    
    #[test]
    fn test_create_and_get_user() {
        let client = Client::tracked(test_rocket()).unwrap();
        
        let response = client.post("/api/users")
            .header(rocket::http::ContentType::JSON)
            .body(r#"{"name":"Alice"}"#)
            .dispatch();
        
        assert_eq!(response.status(), rocket::http::Status::Ok);
        
        let body = response.into_string().unwrap();
        let user: User = serde_json::from_str(&body).unwrap();
        assert_eq!(user.name, "Alice");
        
        let response = client.get(format!("/api/users/{}", user.id))
            .dispatch();
        
        assert_eq!(response.status(), rocket::http::Status::Ok);
    }
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .manage(Db::new())
        .mount("/api", routes![get_user, create_user])
}

下一步 #

掌握了测试后,让我们继续学习 性能优化,了解如何优化Rocket应用性能。

最后更新:2026-03-28