mirror of
https://codeberg.org/JasterV/test-context.git
synced 2026-04-26 18:10:06 +00:00
* [FIX-CONFLICT-WITH-RSTEST-V2]: semi-stable version, fix test_context function, remove unnecessary field, remove wrapper function, add ability to work with rstest and same * [FIX-CONFLICT-WITH-RSTEST-V2]: stable version, fix bugs with AssertUnwindSafe in sync_wrapper_body, remove redundant code, fix two tests, add notes for this tests * [FIX-CONFLICT-WITH-RSTEST-V2]: stable version, fix context name extraction function, fix readme, fix docs, increase version of crate --------- Co-authored-by: Vyacheslav Volkov <v.volkov@st-falcon.ru>
216 lines
5.1 KiB
Markdown
216 lines
5.1 KiB
Markdown
[](https://crates.io/crates/test-context)
|
|
[](https://docs.rs/test-context)
|
|

|
|
[](https://github.com/markhildreth/test-context/actions)
|
|
|
|
# test-context
|
|
|
|
A library for providing custom setup/teardown for Rust tests without needing a test harness.
|
|
|
|
```rust
|
|
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`.
|
|
|
|
```rust
|
|
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`](https://docs.rs/actix-rt/1.1.1/actix_rt/attr.test.html) or
|
|
[`tokio::test`](https://docs.rs/tokio/1.0.2/tokio/attr.test.html).
|
|
|
|
```rust
|
|
#[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:
|
|
|
|
```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.5", 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
|
|
|
|
Also, if you don't care about the
|
|
teardown execution for a specific test, you can use the `skip_teardown` keyword on the macro
|
|
like this:
|
|
|
|
```rust
|
|
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: &mut MyContext) {
|
|
// Perform any operations that require full ownership of your context
|
|
}
|
|
```
|
|
|
|
## ⚠️ Ensure that the context type specified in the macro matches the test function argument type exactly
|
|
|
|
The error occurs when a context type with an absolute path is mixed with an it's alias.
|
|
|
|
For example:
|
|
|
|
```
|
|
mod database {
|
|
use test_context::TestContext;
|
|
|
|
pub struct Connection;
|
|
|
|
impl TestContext for :Connection {
|
|
fn setup() -> Self {Connection}
|
|
fn teardown(self) {...}
|
|
}
|
|
}
|
|
```
|
|
|
|
✅The following code will work:
|
|
```
|
|
use database::Connection as DbConn;
|
|
|
|
#[test_context(DbConn)]
|
|
#[test]
|
|
fn test1(ctx: &mut DbConn) {
|
|
//some test logic
|
|
}
|
|
|
|
// or
|
|
|
|
use database::Connection
|
|
|
|
#[test_context(database::Connection)]
|
|
#[test]
|
|
fn test1(ctx: &mut database::Connection) {
|
|
//some test logic
|
|
}
|
|
```
|
|
|
|
❌The following code will not work:
|
|
```
|
|
use database::Connection as DbConn;
|
|
|
|
#[test_context(database::Connection)]
|
|
#[test]
|
|
fn test1(ctx: &mut DbConn) {
|
|
//some test logic
|
|
}
|
|
|
|
// or
|
|
|
|
use database::Connection as DbConn;
|
|
|
|
#[test_context(DbConn)]
|
|
#[test]
|
|
fn test1(ctx: &mut database::Connection) {
|
|
//some test logic
|
|
}
|
|
```
|
|
|
|
Type mismatches will cause context parsing to fail during either static analysis or compilation.
|
|
|
|
|
|
License: MIT
|