| Crates.io | teststack |
| lib.rs | teststack |
| version | 0.1.0 |
| created_at | 2025-06-20 14:08:53.422695+00 |
| updated_at | 2025-06-20 14:08:53.422695+00 |
| description | Test utilities to run testcontainers |
| homepage | |
| repository | https://github.com/luca-iachini/teststack |
| max_upload_size | |
| id | 1719693 |
| size | 107,303 |
Teststack is a Rust utility crate that simplifies the setup and management of reusable test containers using the testcontainers library. It starts each container once per test suite and shares it across tests, reducing overhead and complexity.
Add teststack to your Cargo.toml:
[dev-dependencies]
teststack = { version = "0.1", features = ["postgres"] }
In the example below, both tests share the same Postgres container instance. This reduces startup overhead and speeds up test execution. The container is automatically shut down at the end of the test harness.
use teststack::stack;
#[stack(postgres(random_db_name))]
#[sqlx::test]
async fn test(pool: PgPool) {
sqlx::query("SELECT 1")
.fetch_one(&pool)
.await
.expect("failed to execute query");
}
The following example demonstrates how to run a RabbitMq container using teststack. It shows how to customize an existing testcontainers_module image with the ImageExt trait for advanced configuration.
use testcontainers_modules::rabbitmq::RabbitMq;
use testcontainers_modules::testcontainers::{ContainerRequest, ImageExt};
use teststack::DbContainer;
use teststack::{ContainerPort, CustomContainer, stack};
#[stack(container(rabbit()))]
#[tokio::test]
async fn test(rabbit: RabbitConnection) {
rabbit
.create_channel()
.await
.expect("failed to create channel");
}
fn rabbit() -> ContainerRequest<RabbitMq> {
RabbitMq::default().with_tag("3.11.0-alpine")
}
struct RabbitConnection(lapin::Connection);
impl std::ops::Deref for RabbitConnection {
type Target = lapin::Connection;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl teststack::Init<RabbitConnection> for CustomContainer {
async fn init(self) -> RabbitConnection {
let port = self
.get_host_port_ipv4(ContainerPort::Tcp(5672))
.await
.unwrap();
let url = format!("amqp://guest:guest@localhost:{port}");
let conn = lapin::Connection::connect(&url, lapin::ConnectionProperties::default())
.await
.unwrap();
RabbitConnection(conn)
}
}
If you don't need any custom configuration, you can simplify the container setup by returning the image directly:
use testcontainers_modules::rabbitmq::RabbitMq;
use teststack::{CustomContainer, stack};
#[stack(container(RabbitMq::default()))]
#[tokio::test]
async fn test(rabbit: CustomContainer) {
// test
}
All containers are shared per image type. Cleanup is performed once, when the test process exits or receives a Ctrl+C signal.
Test containers are gracefully cleaned up on process exit using ctor and dtor, with support for both async and blocking cleanup.
postgres – enable PostgreSQL test container supportmysql – enable MySQL test container support