我正在使用actix-web编写一个小服务,我正在添加集成测试来评估功能,并注意到在每个测试中,我必须重复与主应用程序中相同的定义,除了它被测试服务 Package :
let app = test::init_service(App::new().service(health_check)).await;
如果您有简单的服务,这可以很容易地扩展,但当中间件和更多配置开始添加时,测试开始变得庞大,此外,可能很容易错过一些东西,而不是评估与主应用程序相同的规格。
我一直试图从主线程中提取App,以便能够在我的测试中重用它,但没有成功。具体来说,我想为App创建一个“工厂”:
pub fn get_app() -> App<????> {
App::new()
.wrap(Logger::default())
.wrap(IdentityService::new(policy))
.service(health_check)
.service(login)
}
这样我就可以在测试中写
let app = get_app();
let service = test::init_service(app).await;
但是编译器需要特定的返回类型,它似乎是一个由几个traits和struct组成的chorizo,其中一些是私有的。
有人有过这样的经验吗?
谢谢!
2条答案
按热度按时间h43kikqp1#
定义一个声明性宏
app!
来构建App
,但使用过程API定义路由,而不是使用Actix内置宏(如#[get("/")]
)。这个例子使用数据库池作为state-您的应用程序可能有不同种类的状态或者根本没有状态。
这可在测试中用作:
在主应用程序中为:
在这种情况下,
get_main_pool
必须返回,比如说,Result<sqlx::Pool<sqlx::Postgres>, std::io::Error>
,才能与actix_web::main
的签名要求兼容,另一方面,get_test_pool
可以简单地返回sqlx::Pool<sqlx::Postgres>
。cu6pst1q2#
我在使用
actix-web@4
时也遇到了同样的问题,但我想出了一个可能的解决方案。它可能不太理想,但符合我的需要。我需要在Cargo.toml
中引入actix-service@2.0.2
和actix-http@3.2.2
。我创建了一个带有初始化器的
test.rs
文件,它可以在所有测试中使用。我在API服务中使用它来减少集成测试中的样板文件。
我相信您遇到的问题是尝试为
App
(在Actix中有点反模式)而不是init_service
创建工厂。如果您想创建一个返回App的函数,我相信首选约定是使用configure
。请参阅此问题以获取参考:https://github.com/actix/actix-web/issues/2039 .