我想在我的处理程序函数中从HttpRequest
中提取我的HttpRequest
结构。当我通过我的主要应用程序实例调用该处理程序时,它可以工作,但在集成测试中不能工作。
处理程序功能:
pub async fn handle(req: HttpRequest, user: Json<NewUser>) -> Result<HttpResponse, ShopError> {
let state = req.app_data::<Data<AppState>>().expect("app_data is empty!");
Ok(HttpResponse::Ok().finish())
}
main.rs:
#[actix_web::main]
pub async fn main() -> std::io::Result<()> {
dotenv().ok();
let chat_server = Lobby::default().start();
let state = AppState {
static_data: String::from("my_data")
};
HttpServer::new(move || {
App::new()
.app_data(Data::new(state.clone()))
.service(web::scope("/").configure(routes::router))
.app_data(Data::new(chat_server.clone()))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
测试:
#[actix_web::test]
async fn sanity_test() {
let app = test::init_service(App::new().route("/", web::post().to(handle))).await;
let user = NewUser {
username: String::from("legit_user"),
password: String::from("123"),
};
let state = AppState {
static_data: String::from("my_data")
};
let req = test::TestRequest::post()
.app_data(Data::new(state))
.set_json(&user)
.uri("/")
.to_request();
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success());
}
测试输出:
running 1 test
thread 'routes::login::tests::sanity_test' panicked at 'app_data is empty!', src/routes/login.rs:35:50
出于某种原因,它总是None
。我尝试过使用Data<AppState>
提取器,但是整个处理程序甚至不会被调用,同样,只在测试时调用,否则一切都正常。
Cargo.toml:
[dependencies]
diesel = { version = "1.4.4", features = ["postgres", "r2d2", "chrono"] }
diesel_migrations = "1.4.0"
chrono = { version = "0.4.19", features = ["serde"] }
dotenv = "0.15.0"
actix = "0.13.0"
actix-web = "4.1.0"
actix-web-actors = "4.1.0"
bcrypt = "0.13.0"
uuid = { version = "1.1.2", features = ["serde", "v4"] }
serde_json = "1.0.82"
serde = { version = "1.0.139", features = ["derive"] }
validator = { version = "0.16.0", features = ["derive"] }
derive_more = "0.99.17"
r2d2 = "0.8.10"
lazy_static = "1.4.0"
jsonwebtoken = "8.1.1"
我知道app_data is always None in request handler线程,它不能解决我的问题,因为对我来说,除了测试之外,一切都能工作。
发布于 2022-08-15 10:50:51
根据我在集成测试中所看到的,app_data不是为传递给test::init_service的应用实例配置的,这就是处理程序恐慌的原因。当应用程序配置了app_data,就像您在main中所做的那样,app_data就可以用于处理程序了。
通过下面的代码,处理程序可以在集成测试中访问AppData。与原始帖子的主要区别在于,集成测试中的应用程序配置的是app_data,而不是请求。
use actix_web::{
HttpServer,
HttpRequest,
HttpResponse,
App,
web::{Data, Json},
post,
};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
pub struct NewUser{
username: String,
password: String,
}
#[derive(Clone)]
struct AppState{
static_data: String,
}
#[post("/")]
pub async fn handle(
req: HttpRequest,
_user: Json<NewUser>
) -> HttpResponse {
let state = req
.app_data::<Data<AppState>>()
.expect("app_data is empty!");
println!("Static data: {}", state.static_data);
HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let state = AppState{
static_data: "Sparta".to_string(),
};
HttpServer::new(move || {
App::new()
.app_data(Data::new(state.clone()))
.service(handle)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
#[cfg(test)]
mod tests {
use super::*;
use actix_web::{
test,
};
#[actix_web::test]
async fn itest() {
// Set up app with test::init_service
let state = AppState {
static_data: "Sparta".to_string(),
};
let app = test::init_service(
App::new()
.app_data(Data::new(state.clone()))
.service(handle)
).await;
// Prepare request
let sample_user = NewUser{
username: "legit_user".to_string(),
password: "nosecret123".to_string(),
};
let req = test::TestRequest::post()
.set_json(&sample_user)
.uri("/")
.to_request();
// Send request and await response
let resp = test::call_service(&app, req).await;
assert!(resp.status().is_success())
}
}
https://stackoverflow.com/questions/73319749
复制相似问题