Actix-web 集成测试:重用主线程应用程序

Ray*_*Ray 7 integration-testing rust actix-web

我正在使用 actix-web 编写一个小型服务。我添加集成测试来评估功能,并注意到在每次测试中我都必须重复主应用程序中的相同定义,除了它由测试服务包装之外:

let app = test::init_service(App::new().service(health_check)).await;
Run Code Online (Sandbox Code Playgroud)

如果您有简单的服务,那么这可以很容易地扩展,但是当开始添加中间件和更多配置时,测试开始变得庞大,此外,可能很容易错过一些东西并且不评估与主应用程序相同的规格。

我一直在尝试从主线程中提取应用程序,以便能够在我的测试中重用它,但没有成功。具体来说,我想要的是为应用程序创建一个“工厂”:

pub fn get_app() -> App<????> {
App::new()
            .wrap(Logger::default())
            .wrap(IdentityService::new(policy))
            .service(health_check)
            .service(login)
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以在测试中写下这个

let app = get_app();
let service =  test::init_service(app).await;
Run Code Online (Sandbox Code Playgroud)

但是编译器需要特定的返回类型,它似乎是由几个特征和结构组成的香肠,其中一些是私有的。

有人有这方面的经验吗?

谢谢!

Ovi*_*ies 0

定义一个app!构建 的声明性宏App,但使用过程 API 定义路由,而不是 Actix 内置宏,例如#[get("/")].

此示例使用数据库池作为状态- 您的应用程序可能有不同类型的状态或根本没有状态。

#[macro_export]
macro_rules! app (
    ($pool: expr) => ({
        App::new()
            .wrap(middleware::Logger::default())
            .app_data(web::Data::new($pool.clone()))
            .route("/health", web::get().to(health_get))
            .service(web::resource("/items")
                .route(web::get().to(items_get))
                .route(web::post().to(items_post))
            )
    });
);
Run Code Online (Sandbox Code Playgroud)

这可以在测试中用作:

#[cfg(test)]
mod tests {
    // more code here for get_test_pool
    #[test]
    async fn test_health() {
        let app = test::init_service(app!(get_test_pool().await)).await;

        let req = test::TestRequest::get().uri("/health").to_request();
        let resp = test::call_service(&app, req).await;
        assert!(resp.status().is_success());
    }
}
Run Code Online (Sandbox Code Playgroud)

在主应用程序中为:

#[cfg(test)]
mod tests {
    // more code here for get_test_pool
    #[test]
    async fn test_health() {
        let app = test::init_service(app!(get_test_pool().await)).await;

        let req = test::TestRequest::get().uri("/health").to_request();
        let resp = test::call_service(&app, req).await;
        assert!(resp.status().is_success());
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,get_main_pool必须返回,例如,Result<sqlx::Pool<sqlx::Postgres>, std::io::Error>与 的签名要求兼容actix_web::main。另一方面,get_test_pool可以简单地返回sqlx::Pool<sqlx::Postgres>