Testing / 测试
Status: Phase 3+ Available ✅ 状态: 第3阶段+可用 ✅
Hiver provides comprehensive testing support including unit tests, integration tests, and data layer testing. Hiver 提供全面的测试支持,包括单元测试、集成测试和数据层测试。
Overview / 概述
Testing strategies: 测试策略:
- Unit Tests / 单元测试 — Test individual handlers and extractors
- Integration Tests / 集成测试 — Test with
TestClient - E2E Tests / 端到端测试 — Test full application flow
- Data Layer Tests / 数据层测试 — Test repositories and ORM models
Unit Testing / 单元测试
Testing Handlers / 测试处理器
#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_handler() -> std::io::Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let response = handler(Request::default()).await;
assert_eq!(response.status(), StatusCode::OK);
Ok(())
})
}
}
}
Testing Extractors / 测试提取器
#![allow(unused)]
fn main() {
#[test]
fn test_path_extractor() -> std::io::Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let req = Request::builder()
.uri("/users/123")
.build();
let id: Path<u64> = Path::from_request(&req).await.unwrap();
assert_eq!(id.0, 123);
Ok(())
})
}
}
Testing JSON Serialization / 测试 JSON 序列化
#![allow(unused)]
fn main() {
#[test]
fn test_json_response() {
let user = User {
id: 1,
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
let json = serde_json::to_string(&user).unwrap();
assert!(json.contains("Alice"));
let deserialized: User = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.id, 1);
}
}
Integration Testing / 集成测试
TestClient / 测试客户端
#![allow(unused)]
fn main() {
use hiver_test::TestClient;
#[test]
fn test_api() -> std::io::Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let app = create_app();
let client = TestClient::new(app);
// Test GET / 测试 GET
let response = client.get("/api/users").send().await;
assert_eq!(response.status(), 200);
// Test POST / 测试 POST
let response = client.post("/api/users")
.json(&user_data)
.send()
.await;
assert_eq!(response.status(), 201);
// Test with headers / 测试带请求头
let response = client.get("/api/profile")
.header("Authorization", "Bearer token123")
.send()
.await;
assert_eq!(response.status(), 200);
Ok(())
})
}
}
Testing Middleware / 测试中间件
#![allow(unused)]
fn main() {
#[test]
fn test_cors_middleware() -> std::io::Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let cors = Cors::new()
.allow_origin("*")
.allow_methods(["GET", "POST"]);
let app = Router::new()
.middleware(Arc::new(cors))
.get("/", || async { "ok" });
let client = TestClient::new(app);
let response = client.get("/").send().await;
assert_eq!(
response.headers().get("Access-Control-Allow-Origin").unwrap(),
"*"
);
Ok(())
})
}
}
Data Layer Testing / 数据层测试
Testing Repository / 测试仓库
#![allow(unused)]
fn main() {
use hiver_data_rdbc::DatabaseClient;
use hiver_data_orm::prelude::*;
#[test]
fn test_repository_crud() -> Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
// Use test database / 使用测试数据库
let client = DatabaseClient::connect("sqlite::memory:").await?;
let repo = UserRepository::new(client);
// Create / 创建
let user = repo.save(User {
name: "Alice".to_string(),
email: "alice@test.com".to_string(),
..Default::default()
}).await?;
assert!(user.id > 0);
// Read / 读取
let found = repo.find_by_id(user.id).await?;
assert_eq!(found.unwrap().name, "Alice");
// Update / 更新
let updated = repo.save(User {
id: user.id,
name: "Alice Updated".to_string(),
email: "alice@test.com".to_string(),
}).await?;
assert_eq!(updated.name, "Alice Updated");
// Delete / 删除
repo.delete_by_id(user.id).await?;
assert!(repo.find_by_id(user.id).await?.is_none());
Ok(())
})
}
}
Testing Query Methods / 测试查询方法
#![allow(unused)]
fn main() {
#[test]
fn test_derived_queries() -> Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let repo = setup_test_repo().await?;
// Test findBy... / 测试 findBy...
let users = repo.find_by_email("alice@test.com").await?;
assert_eq!(users.len(), 1);
// Test findBy...And... / 测试 findBy...And...
let users = repo.find_by_name_and_email("Alice", "alice@test.com").await?;
assert_eq!(users.len(), 1);
// Test pagination / 测试分页
let page = repo.find_all(PageRequest::of(0, 10)).await?;
assert!(page.total_elements() > 0);
Ok(())
})
}
}
Testing Migrations / 测试迁移
#![allow(unused)]
fn main() {
use hiver_flyway::{Flyway, MigrationConfig};
#[test]
fn test_migrations() -> Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let mut flyway = Flyway::new(MigrationConfig {
locations: vec!["migrations".to_string()],
..Default::default()
});
let result = flyway.migrate(&mut conn).await?;
assert_eq!(result.successful_migrations, 3);
Ok(())
})
}
}
E2E Testing / 端到端测试
#![allow(unused)]
fn main() {
#[test]
fn test_full_flow() -> std::io::Result<()> {
let rt = hiver_runtime::Runtime::new()?;
rt.block_on(async {
let server = start_test_server().await;
let client = reqwest::Client::new();
// Create user / 创建用户
let response = client
.post("http://localhost:8080/api/users")
.json(&json!({"name": "Alice", "email": "alice@test.com"}))
.send().await.unwrap();
assert_eq!(response.status(), 201);
// Get user / 获取用户
let response = client
.get("http://localhost:8080/api/users/1")
.send().await.unwrap();
assert_eq!(response.status(), 200);
Ok(())
})
}
}
Test Organization / 测试组织
my-app/
├── src/
│ ├── lib.rs
│ └── handler.rs # #[cfg(test)] mod tests { ... }
├── tests/
│ ├── api_test.rs # Integration tests
│ └── data_test.rs # Data layer tests
└── migrations/
├── V1__create_users.sql
└── V2__add_posts.sql
Best Practices / 最佳实践
- Test in isolation — mock external dependencies / 隔离测试,模拟外部依赖
- Use
sqlite::memory:for data tests — fast, no setup / 数据测试用内存 SQLite - Test error cases — verify error responses / 测试错误情况
- Use
TestClientfor handler tests — no real HTTP needed / 用 TestClient 测试处理器 - Run migrations before data tests — ensure schema is current / 数据测试前先跑迁移
← Previous / 上一页 | Next / 下一页 →