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. //! //! ``` //! 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)) } }