Miko 框架系列(十四):集成测试
注意:此文章主要为了给支持联网搜索的AI提供RAG,此项目还在开发阶段,不建议用于生产。
测试是保证软件质量的关键环节。在 Web 开发中,集成测试(Integration Testing)尤为重要,因为它能验证路由、中间件、提取器和业务逻辑是否作为一个整体协同工作。
Miko 提供了一个强大的 TestClient 工具,专门用于进行**进程内(In-Process)**的集成测试。它不仅速度极快,而且能模拟真实的请求处理流程。
1. 核心优势
- 极速执行:绕过网络协议栈,直接在内存中分发请求,测试运行速度比通过 HTTP 接口测试快数倍。
- 无需端口:测试在同一个进程内运行,不需要绑定 TCP 端口,避免了端口冲突问题,也支持并行运行测试。
- 全链路覆盖:完整触发路由解析、请求提取器、中间件(Layers)以及依赖注入逻辑。
- 环境一致性 :配合 Miko 的
build模式,确保测试环境与生产环境配置完全一致。
2. 启用测试支持
首先,在 Cargo.toml 中启用 test feature:
toml
[dev-dependencies]
miko = { version = "0.7", features = ["test", "full"] }
3. 基础用法:测试 Router
如果你只想测试一部分路由逻辑,可以直接在 Router 实例上调用 test_client()。
rust
use miko::{Router, TestClient};
#[tokio::test]
async fn test_basic_router() {
let mut router = Router::new();
router.get("/ping", || async { "pong" });
// 创建测试客户端
let client = router.test_client();
// 发送请求并断言
client.get("/ping")
.send()
.await
.assert_status(200)
.assert_text("pong");
}
4. 进阶用法:全量应用测试
对于实际应用,我们通常需要测试完整的应用程序,包括依赖注入、配置和全局中间件。Miko 推荐使用 build 模式来进行全量测试。
第一步:改造应用入口
在 src/main.rs 中,将应用构建逻辑抽取出来,并使用 #[miko(build)] 宏。这会生成一个可供测试调用的构建函数。
rust
// src/main.rs
use miko::*;
// 添加 build 参数
// 这会生成一个名为 `create_app` 的 public async 函数
#[miko(build)]
async fn main() {
let mut router = Router::new();
router.get("/", || async { "Hello Miko" });
// ... 注册其他路由和组件
}
第二步:编写集成测试
在 tests/ 目录下,引用主程序模块,并使用生成好的 create_app 函数。
rust
// tests/app_test.rs
// 引用 src/main.rs
#[path = "../src/main.rs"]
mod app;
#[tokio::test]
async fn test_full_application() {
// 1. 获取全量配置的应用实例 (包括 DI 容器初始化、配置加载等)
let mut app = app::create_app().await;
// 2. 创建客户端
let client = app.test_client();
// 3. 执行测试
client.get("/").send().await.assert_text("Hello Miko");
}
5. 构造请求与断言
TestClient 提供了类似 reqwest 的链式 API,让你能轻松构造各种请求,并对响应进行丰富的断言。
rust
use serde_json::json;
#[tokio::test]
async fn test_create_user() {
// ... 初始化 client ...
let res = client.post("/api/users")
.header("Authorization", "Bearer my-token")
.json(&json!({
"username": "test_user",
"email": "test@example.com"
}))
.send()
.await;
// 状态码断言
res.assert_status(201);
// Header 断言
res.assert_header("Content-Type", "application/json");
// JSON Body 断言
res.assert_json(json!({
"success": true,
"username": "test_user"
}));
}
常用断言方法
assert_ok(): 断言状态码为 2xx。assert_status(code): 断言特定的 HTTP 状态码。assert_header(key, value): 断言响应头存在且值匹配。assert_text(expected): 断言响应体文本内容。assert_json(expected): 断言响应体匹配给定的 JSON (支持部分匹配)。assert_contains(text): 断言响应体包含特定文本。
6. 测试依赖注入 (DI)
当使用 create_app() 模式时,DI 容器会自动初始化。如果你需要手动控制,可以使用 miko::auto::init_container()。
rust
#[tokio::test]
async fn test_with_di() {
// 手动初始化 DI 容器
miko::auto::init_container().await;
// ...
}
总结
Miko 的 TestClient 为开发者提供了一种高效、可靠的测试手段。通过在进程内模拟请求,它不仅消除了网络开销,还保证了测试环境与生产环境的高度一致性。配合 #[miko(build)] 模式,你可以轻松编写出覆盖率高、运行速度快的集成测试套件。
下一篇预告:Miko 框架系列(十五):版本更新与新特性总览