1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
//! A library for providing custom setup/teardown for Rust tests without needing a test harness.
//!
//! ```no_run
//! 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!");
//! }
//! ```
//!
//! Alternatively, you can use `async` functions in your test context by using the
//! `AsyncTestContext`.
//!
//! ```
//! use test_context::{test_context, AsyncTestContext};
//!
//! struct MyAsyncContext {
//! value: String
//! }
//!
//! #[async_trait::async_trait]
//! 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).
//!
//! ```
//! # use test_context::{test_context, AsyncTestContext};
//! # struct MyAsyncContext {
//! # value: String
//! # }
//! # #[async_trait::async_trait]
//! # 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)]
//! #[tokio::test]
//! async fn test_async_works(ctx: &mut MyAsyncContext) {
//! assert_eq!(ctx.value, "Hello, World!");
//! }
//! ```
// Reimported to allow for use in the macro.
pub use futures;
pub use test_context_macros::test_context;
/// The trait to implement to get setup/teardown functionality for tests.
pub trait TestContext
where
Self: Sized,
{
/// Create the context. This is run once before each test that uses the context.
fn setup() -> Self;
/// Perform any additional cleanup of the context besides that already provided by
/// normal "drop" semantics.
fn teardown(self) {}
}
/// The trait to implement to get setup/teardown functionality for async tests.
#[async_trait::async_trait]
pub trait AsyncTestContext
where
Self: Sized,
{
/// Create the context. This is run once before each test that uses the context.
async fn setup() -> Self;
/// Perform any additional cleanup of the context besides that already provided by
/// normal "drop" semantics.
async fn teardown(self) {}
}
// Automatically impl TestContext for anything Send that impls AsyncTestContext.
//
// A future improvement may be to use feature flags to enable using a specific runtime
// to run the future synchronously. This is the easiest way to implement it, though, and
// introduces no new dependencies.
impl<T> TestContext for T
where
T: AsyncTestContext + Send,
{
fn setup() -> Self {
futures::executor::block_on(<T as AsyncTestContext>::setup())
}
fn teardown(self) {
futures::executor::block_on(<T as AsyncTestContext>::teardown(self))
}
}