Files
rust-user-api/tests/search_api_tests.rs
enoch cf01d557b9 feat: 实现数据库迁移、搜索和分页功能
- 添加数据库迁移系统和初始用户表迁移
- 实现搜索功能模块和API
- 实现分页功能支持
- 添加相关测试文件
- 更新项目配置和文档
2025-08-05 23:44:01 +08:00

332 lines
11 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 搜索API端点测试
use reqwest;
use serde_json::{json, Value};
use tokio;
const BASE_URL: &str = "http://127.0.0.1:3000";
/// 测试辅助函数:创建 HTTP 客户端
fn create_client() -> reqwest::Client {
reqwest::Client::new()
}
/// 测试辅助函数:解析 JSON 响应
async fn parse_json_response(response: reqwest::Response) -> Result<Value, Box<dyn std::error::Error>> {
let text = response.text().await?;
let json: Value = serde_json::from_str(&text)?;
Ok(json)
}
/// 测试辅助函数:创建测试用户
async fn create_test_user(client: &reqwest::Client, username: &str, email: &str) -> Result<Value, Box<dyn std::error::Error>> {
let user_data = json!({
"username": username,
"email": email,
"password": "password123"
});
let response = client
.post(&format!("{}/api/users", BASE_URL))
.json(&user_data)
.send()
.await?;
if response.status().is_success() {
parse_json_response(response).await
} else {
Err(format!("Failed to create user: {}", response.status()).into())
}
}
#[tokio::test]
async fn test_search_api_basic() {
let client = create_client();
// 创建一些测试用户
let test_users = vec![
("search_admin_1", "admin1@company.com"),
("search_user_1", "user1@example.com"),
("search_admin_2", "admin2@company.com"),
("search_manager", "manager@company.com"),
];
for (username, email) in test_users {
let _ = create_test_user(&client, username, email).await;
}
// 测试基本搜索功能
let response = client
.get(&format!("{}/api/users/search?q=admin", BASE_URL))
.send()
.await
.expect("Failed to search users");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
// 验证搜索响应结构
assert!(json["data"].is_array(), "Response should have data array");
assert!(json["pagination"].is_object(), "Response should have pagination object");
assert!(json["search_params"].is_object(), "Response should have search_params object");
assert!(json["total_filtered"].is_number(), "Response should have total_filtered");
let data = json["data"].as_array().unwrap();
let search_params = &json["search_params"];
// 验证搜索参数被正确返回
assert_eq!(search_params["q"], "admin");
// 验证搜索结果
for user in data {
let username = user["username"].as_str().unwrap();
let email = user["email"].as_str().unwrap();
assert!(
username.contains("admin") || email.contains("admin"),
"Search result should contain 'admin' keyword"
);
}
}
#[tokio::test]
async fn test_search_api_with_filters() {
let client = create_client();
// 创建测试用户
let test_users = vec![
("filter_test_1", "test1@example.com"),
("filter_test_2", "test2@company.com"),
("other_user", "other@example.com"),
];
for (username, email) in test_users {
let _ = create_test_user(&client, username, email).await;
}
// 测试用户名过滤
let response = client
.get(&format!("{}/api/users/search?username=filter_test", BASE_URL))
.send()
.await
.expect("Failed to search users by username");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let search_params = &json["search_params"];
// 验证搜索参数
assert_eq!(search_params["username"], "filter_test");
// 验证结果
for user in data {
let username = user["username"].as_str().unwrap();
assert!(username.contains("filter_test"), "Username should contain filter_test");
}
// 测试邮箱过滤
let response = client
.get(&format!("{}/api/users/search?email=company.com", BASE_URL))
.send()
.await
.expect("Failed to search users by email");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let search_params = &json["search_params"];
// 验证搜索参数
assert_eq!(search_params["email"], "company.com");
// 验证结果
for user in data {
let email = user["email"].as_str().unwrap();
assert!(email.contains("company.com"), "Email should contain company.com");
}
}
#[tokio::test]
async fn test_search_api_with_sorting() {
let client = create_client();
// 创建测试用户
let test_users = vec![
("sort_zebra", "zebra@test.com"),
("sort_alpha", "alpha@test.com"),
("sort_beta", "beta@test.com"),
];
for (username, email) in test_users {
let _ = create_test_user(&client, username, email).await;
}
// 测试按用户名升序排序
let response = client
.get(&format!("{}/api/users/search?username=sort_&sort_by=username&sort_order=asc", BASE_URL))
.send()
.await
.expect("Failed to search users with sorting");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let search_params = &json["search_params"];
// 验证搜索参数
assert_eq!(search_params["sort_by"], "username");
assert_eq!(search_params["sort_order"], "asc");
// 验证排序结果
if data.len() > 1 {
for i in 0..data.len() - 1 {
let current_username = data[i]["username"].as_str().unwrap();
let next_username = data[i + 1]["username"].as_str().unwrap();
assert!(
current_username <= next_username,
"Results should be sorted by username in ascending order"
);
}
}
}
#[tokio::test]
async fn test_search_api_with_pagination() {
let client = create_client();
// 创建多个测试用户
for i in 1..=5 {
let username = format!("page_test_{}", i);
let email = format!("page{}@test.com", i);
let _ = create_test_user(&client, &username, &email).await;
}
// 测试第一页
let response = client
.get(&format!("{}/api/users/search?username=page_test&page=1&limit=2", BASE_URL))
.send()
.await
.expect("Failed to search users with pagination");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let pagination = &json["pagination"];
assert_eq!(data.len(), 2, "First page should have 2 users");
assert_eq!(pagination["current_page"], 1);
assert_eq!(pagination["per_page"], 2);
assert!(!pagination["has_prev"].as_bool().unwrap(), "First page should not have previous");
// 测试第二页
let response = client
.get(&format!("{}/api/users/search?username=page_test&page=2&limit=2", BASE_URL))
.send()
.await
.expect("Failed to search users page 2");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let pagination = &json["pagination"];
assert_eq!(data.len(), 2, "Second page should have 2 users");
assert_eq!(pagination["current_page"], 2);
assert!(pagination["has_prev"].as_bool().unwrap(), "Second page should have previous");
}
#[tokio::test]
async fn test_search_api_validation_errors() {
let client = create_client();
// 测试无效的排序字段
let response = client
.get(&format!("{}/api/users/search?sort_by=invalid_field", BASE_URL))
.send()
.await
.expect("Failed to send request with invalid sort field");
assert_eq!(response.status(), 400);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
assert!(json["error"].as_str().unwrap().contains("无效的排序字段"));
// 测试无效的排序方向
let response = client
.get(&format!("{}/api/users/search?sort_order=invalid_order", BASE_URL))
.send()
.await
.expect("Failed to send request with invalid sort order");
assert_eq!(response.status(), 400);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
assert!(json["error"].as_str().unwrap().contains("无效的排序方向"));
}
#[tokio::test]
async fn test_search_api_empty_results() {
let client = create_client();
// 搜索不存在的关键词
let response = client
.get(&format!("{}/api/users/search?q=nonexistent_keyword_12345", BASE_URL))
.send()
.await
.expect("Failed to search for nonexistent keyword");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let total_filtered = json["total_filtered"].as_i64().unwrap();
assert_eq!(data.len(), 0, "Should return empty results");
assert_eq!(total_filtered, 0, "Total filtered should be 0");
}
#[tokio::test]
async fn test_search_api_complex_query() {
let client = create_client();
// 创建测试用户
let test_users = vec![
("complex_admin", "admin@company.com"),
("complex_user", "user@company.com"),
("simple_admin", "admin@example.com"),
];
for (username, email) in test_users {
let _ = create_test_user(&client, username, email).await;
}
// 复合搜索用户名包含admin且邮箱包含company
let response = client
.get(&format!("{}/api/users/search?username=admin&email=company&sort_by=username&sort_order=asc", BASE_URL))
.send()
.await
.expect("Failed to perform complex search");
assert_eq!(response.status(), 200);
let json = parse_json_response(response).await.expect("Failed to parse JSON");
let data = json["data"].as_array().unwrap();
let search_params = &json["search_params"];
// 验证搜索参数
assert_eq!(search_params["username"], "admin");
assert_eq!(search_params["email"], "company");
assert_eq!(search_params["sort_by"], "username");
assert_eq!(search_params["sort_order"], "asc");
// 验证结果同时满足两个条件
for user in data {
let username = user["username"].as_str().unwrap();
let email = user["email"].as_str().unwrap();
assert!(username.contains("admin"), "Username should contain admin");
assert!(email.contains("company"), "Email should contain company");
}
}