4 KiB
test-context
A library for providing custom setup/teardown for Rust tests without needing a test harness.
use test_context::{test_context, TestContext};
struct MyContext {
value: String
}
impl TestContext for MyContext {
fn setup() -> MyContext {
MyContext { value: "Hello, World!".to_string() }
}
fn teardown(self) {
// Perform any teardown you wish.
}
}
#[test_context(MyContext)]
#[test]
fn test_works(ctx: &mut MyContext) {
assert_eq!(ctx.value, "Hello, World!");
}
struct MyGenericContext<T> {
value: T
}
impl TestContext for MyGenericContext<u32> {
fn setup() -> MyGenericContext<u32> {
MyGenericContext { value: 1 }
}
}
#[test_context(MyGenericContext<u32>)]
#[test]
fn test_generic_type(ctx: &mut MyGenericContext<u32>) {
assert_eq!(ctx.value, 1);
}
Alternatively, you can use async functions in your test context by using the
AsyncTestContext.
use test_context::{test_context, AsyncTestContext};
struct MyAsyncContext {
value: String
}
impl AsyncTestContext for MyAsyncContext {
async fn setup() -> MyAsyncContext {
MyAsyncContext { value: "Hello, World!".to_string() }
}
async fn teardown(self) {
// Perform any teardown you wish.
}
}
#[test_context(MyAsyncContext)]
fn test_works(ctx: &mut MyAsyncContext) {
assert_eq!(ctx.value, "Hello, World!");
}
The AsyncTestContext works well with async test wrappers like
actix_rt::test or
tokio::test.
#[test_context(MyAsyncContext)]
#[tokio::test]
async fn test_works(ctx: &mut MyAsyncContext) {
assert_eq!(ctx.value, "Hello, World!");
}
Attribute order
Place #[test_context(...)] before other test attributes like #[tokio::test] or #[test].
Why: Attributes expand in source order. #[test_context] generates a wrapper and reattaches
the remaining attributes to it. It must run first so the test attribute applies to the wrapper
that runs setup/teardown.
Valid:
#[test_context(MyAsyncContext)]
#[tokio::test]
async fn my_test(ctx: &mut MyAsyncContext) {}
Invalid:
#[tokio::test]
#[test_context(MyAsyncContext)]
async fn my_test(ctx: &mut MyAsyncContext) {}
Using AsyncTestContext in sync tests that require Tokio
By default, when you use an AsyncTestContext in a synchronous test (no #[tokio::test]),
this crate runs setup/teardown using the futures executor. If your context calls
Tokio-only APIs (e.g., tokio::time::sleep, timers, or Tokio sockets) during setup/teardown,
enable the optional tokio-runtime feature so those steps run inside a Tokio runtime:
[dependencies]
test-context = { version = "0.4", features = ["tokio-runtime"] }
With this feature, the crate tries to reuse an existing runtime; if none is present, it creates
an ephemeral current-thread Tokio runtime around setup and teardown for sync tests. Async
tests annotated with #[tokio::test] continue to work as usual without the feature.
Skipping the teardown execution
If what you need is to take full ownership of the context and don't care about the
teardown execution for a specific test, you can use the skip_teardown keyword on the macro
like this:
use test_context::{test_context, TestContext};
struct MyContext {}
impl TestContext for MyContext {
fn setup() -> MyContext {
MyContext {}
}
}
#[test_context(MyContext, skip_teardown)]
#[test]
fn test_without_teardown(ctx: MyContext) {
// Perform any operations that require full ownership of your context
}
License: MIT