diff --git a/README.md b/README.md index 385bd65..6dc70f7 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,46 @@ async fn test_works(ctx: &mut MyAsyncContext) { } ``` +### 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: + +```rust +#[test_context(MyAsyncContext)] +#[tokio::test] +async fn my_test(ctx: &mut MyAsyncContext) {} +``` + +Invalid: + +```rust +#[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: + +```toml +[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 diff --git a/test-context/src/lib.rs b/test-context/src/lib.rs index 08d01cd..1a09375 100644 --- a/test-context/src/lib.rs +++ b/test-context/src/lib.rs @@ -78,6 +78,29 @@ //! } //! ``` //! +//! # Attribute order +//! +//! Attribute order matters. Always place `#[test_context(...)]` before other test attributes +//! like `#[tokio::test]` or `#[test]`. +//! +//! Why: Rust expands attributes in source order. `#[test_context]` wraps your function and +//! re-attaches the remaining attributes to the wrapper; it must run first so the test attributes +//! apply to the wrapper that performs setup/teardown. +//! +//! Valid: +//! ```ignore +//! #[test_context(MyAsyncContext)] +//! #[tokio::test] +//! async fn my_test(ctx: &mut MyAsyncContext) {} +//! ``` +//! +//! Invalid: +//! ```ignore +//! #[tokio::test] +//! #[test_context(MyAsyncContext)] +//! async fn my_test(ctx: &mut MyAsyncContext) {} +//! ``` +//! //! # Skipping the teardown execution //! //! If what you need is to take full __ownership__ of the context and don't care about the