use crate::routes::routes;
use actix_web::dev::ServiceResponse;
use actix_web::{test, App};
// 测试get
pub async fn test_get(route: &str) -> ServiceResponse {
let mut app = test::init_service(App::new().configure(routes)).await;
test::call_service(&mut app, test::TestRequest::get().uri(route).to_request()).await
}
// assert get 方法
pub async fn assert_get(route: &str) -> ServiceResponse {
let response = test_get(route).await;
assert!(response.status().is_success());
response
}
handlers.rs:
use crate::tests::helpers::assert_get;
#[actix_rt::test]
async fn test_hello_world() {
assert_get("/").await;
}
运行测试:
$ cargo test
running 1 test
test tests::handlers::tests::test_hello_world ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
#[actix_rt::test]
async fn test_create_todos() {
let todo_title = "Create todo List";
let params = CreateTodoList {
title: todo_title.into(),
};
let response = assert_post("/todos", params).await;
// 检查放返回数据
let body = test::read_body(response).await;
let try_created: Result<models::TodoList, serde_json::error::Error> =
serde_json::from_slice(&body);
assert!(try_created.is_ok(), "Response couldn't not be parsed");
// 使用接口查看数据
let created_list = try_created.unwrap();
let resp = assert_get("/todos").await;
let todos: Vec<models::TodoList> = test::read_body_json(resp).await;
let maybe_list = todos.iter().find(|todo| todo.id == created_list.id);
assert!(maybe_list.is_some(), "Item not found!");
}
$ cargo test
running 2 tests
test tests::handlers::test_hello_world ... ok
test tests::handlers::test_create_todos ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
测试 GET 接口
最后添加 GET 集成测试:
use crate::db::create_todo;
use crate::tests::helpers::{assert_get, assert_post, APP_STATE};
use deadpool_postgres::Client;
// ...
#[actix_rt::test]
async fn test_get_todos() {
// create data in db
let todo_title = "New Todo List";
let client: Client = APP_STATE
.pool
.get()
.await
.expect("Error connecting to the database");
let new_todo = create_todo(&client, todo_title.into()).await;
assert!(new_todo.is_ok(), "Failed to create new test todo");
// get and check
let new_todo = new_todo.unwrap();
let response = assert_get("/todos").await;
let todos: Vec<models::TodoList> = test::read_body_json(response).await;
let maybe_list = todos.iter().find(|todo| todo.id == new_todo.id);
assert!(maybe_list.is_some(), "Item not found!");
}
运行结果:
$ cargo test
running 3 tests
test tests::handlers::test_hello_world ... ok
test tests::handlers::test_get_todos ... ok
test tests::handlers::test_create_todos ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
对程序进行集成测试。
测试前重构
在测试前,先简单重构,方便构建测试。
1. 将路由抽取成单独的模块
routes.rs
并将原来的
hello
视图移至handlers.rs
中,此时main.rs
中路由修改为如下:2. 增加
init_pool
方法首先我们添加一个配置错误处理:
errors.rs
:在
config.rs
中增加init_pool
方法:测试
首先,增加运行时环境包:
创建
tests
目录,并添加如下文件,在 main.rs 中增加
tests
模块:其中,
handlers.rs
用于集成测试,helpers.rs
提供基本的测试方法。mod.rs
:我们先测试一下
/
路由下hello world
的功能。helpers.rs
中增加基本的get
测试方法:handlers.rs
:运行测试:
可以看到这个测试成功了。
测试
POST
接口我们增加
lazy_static
和serde_json
库,前者用于延后执行,后者用于方便处理 json 数据。在集成测试中,我们将使用数据库链接进行测试,首先
helpers.rs
中增加AppState
用于测试:以及对应的 post 测试断言:
然后,我们增加一个创建 todo_list 的测试,包含创建并检测是否存在:
tests/handlers.rs
:其中
CreateTodoList
需要增加Clone
宏,才能在传入params
参数时正常使用。运行测试,查看结果
测试
GET
接口最后添加
GET
集成测试:运行结果:
小结
GET
和POST
测试。参考文档和项目