Rust与Docker集成测试:完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

使用 Docker 进行 Rust 集成测试:从理论到实践



现代 Rust 开发不仅需要检查单个函数(单元测试),还需要测试组件与外部服务(数据库、缓存、API)的交互。使用 Docker 进行集成测试可以隔离环境、保证可重复性,并避免"在我机器上能运行"的问题。本文将分析如何为 Rust 应用设置使用 Docker 的集成测试。



为什么选择 Docker 进行 Rust 集成测试?

Docker 解决了三个关键问题:

  • 环境隔离 — 测试在干净的容器中运行,不受本地设置影响
  • 可重复性 — 在所有开发机器和 CI/CD 中条件一致
  • 依赖管理 — 自动启动 PostgreSQL、Redis、Kafka 及其他服务


项目设置:结构与依赖

让我们创建一个集成测试项目,针对与 PostgreSQL 配合使用的 Actix-web 网络服务器。



# Cargo.toml[package]name = "rust-docker-testing"version = "0.1.0"edition = "2021"

[dependencies]actix-web = "4"serde = { version = "1", features = ["derive"] }tokio = { version = "1", features = ["full"] }sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"] }dotenv = "0.15"

[dev-dependencies]testcontainers = "0.14"reqwest = { version = "0.11", features = ["json"] }


注意 testcontainers — 这是一个 Rust 库,用于直接从测试中管理 Docker 容器。



项目结构

推荐用于集成测试的结构:

.├── src/│   ├── main.rs│   ├── lib.rs│   ├── models.rs│   └── handlers.rs├── tests/│   ├── common/│   │   └── mod.rs          # 测试的通用工具│   ├── integration_tests.rs # 主要集成测试│   └── docker-compose.yml  # 用于手动启动├── Dockerfile└── .env


步骤 1:使用 Docker 编写集成测试

让我们创建一个测试,在 Docker 中启动 PostgreSQL,运行迁移,并检查 API。



// tests/integration_tests.rsuse testcontainers::clients;use testcontainers::images::postgres::Postgres;use sqlx::postgres::PgPoolOptions;use std::net::TcpListener;

async fn setup_test_db() -> (String, testcontainers::Container) { let docker = clients::Cli::default(); let postgres_image = Postgres::default(); let container = docker.run(postgres_image); let host = container.get_host().unwrap(); let port = container.get_host_port_ipv4(5432).unwrap(); let database_url = format!("postgres://postgres:postgres@{}:{}/postgres", host, port); // 执行迁移 let pool = PgPoolOptions::new() .max_connections(5) .connect(&database_url) .await .expect("无法连接到 Postgres"); sqlx::query("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL)") .execute(&pool) .await .expect("迁移失败"); (database_url, container)}

#[tokio::test]async fn test_create_user() { let (db_url, _container) = setup_test_db().await; // 在随机端口启动应用 let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); let server = actix_web::HttpServer::new(move || { actix_web::App::new() .app_data(actix_web::web::Data::new(db_url.clone())) .route("/users", actix_web::web::post().to(handlers::create_user)) }) .listen(listener) .unwrap() .run(); tokio::spawn(server); // 等待服务器启动 tokio::ti

博客

书籍推荐