testify/
lib.rs

1//! This library provides an extended test suite that allows better and easier organization and
2//! management of your tests. It has support for async tests with tokio out of the box.
3//! 
4//! # Setup
5//! 
6//! To set up the testify test suite, you'll need to add `testify-rs` to your project's
7//! dependencies, and to install `testify` via `cargo install testify-rs`. The last one will only
8//! set up the `cargo testify` command, which you'll use to run your tests from now on.
9//! 
10//! ## Features
11//! 
12//! These are the features you can enable in your project:
13//! - `async-tokio`: Enable support for async tests using tokio as the runtime.
14//! 
15//! # Usage
16//! 
17//! To set up the tests runner, wrap your `main()` function with `#[testify::main]`. This'll expand
18//! to (roughly)
19//! ```
20//! fn main() {
21//!     if std::env::var("DO_NOT_MANUALLY_SET_TESTIFY_ARE_TESTS_BEING_RUN").is_ok() {
22//!         testify::run();
23//!     } else {
24//!         /* YOUR CODE */
25//!     }
26//! }
27//! ```
28//! 
29//! > *This means that the testing code will be built into your binary from now onwards.
30//! > Suggestions and PRs are welcome to solve this issue.*
31//! 
32//! After wrapping your main function with testify's main macro, you're ready to go. In case you
33//! already have any tests set up in your project, replace `#[test]` with `#[testify::test]` and
34//! that will be enough for your code to run in most cases.
35//! 
36//! ## The `#[testify::test]` macro
37//! 
38//! As you've seen in the previous section, replacing `#[test]` with `#[testify::test]` should be
39//! enough to get you started in most cases. Testify's test macro supports a wider set of features
40//! than the default one.
41//! 
42//! ### Test Metadata
43//! 
44//! You can organize your tests better by passing some keyword arguments to the test macro (all
45//! optional):
46//! - `name`: A string literal, which allows you to rename the test function to something prettier
47//!     to be outputted in the console when running the tests.
48//! - `case`: A string literal, it allows you to specify different cases of the same unit being
49//!     tested.
50//! - `tags`: An array of string literals, it allows you to tag your tests for easier filtering
51//!     when running your tests with `cargo testify`, opposed to rust's default test suite with its
52//!     substring filtering.
53//! - `should_panic`: As the name says, passing this argument to the test macro will make the test
54//!     execution being expected to panic, and failing if it does not.
55//! - `should_fail`: Similar to `should_panic`, but for the return types of the test function. In
56//!     this case, `TestTermination.success()` will be expected to return `false`.
57//! 
58//! #### Example
59//! 
60//! ```
61//! // All of the arguments passed to the macro are optional.
62//! #[testify::test(
63//!     name = "Register User",
64//!     case = "Weak Password",
65//!     tags = ["api", "auth"],
66//!     should_fail
67//! )]
68//! fn my_test() -> Result<(), String> {
69//!     /* RUN YOUR CODE */
70//!     Err("The password was too weak.".into())
71//! }
72//! ```
73//! 
74//! ### Async Support
75//! 
76//! Tests support async functions out of the box with the `async-tokio` feature. It's as easy as
77//! making your test async for it to run in a tokio runtime.
78//! 
79//! ```
80//! #[testify::test]
81//! async fn my_async_test() {
82//!     /* RUN YOUR CODE */
83//! }
84//! ```
85//! 
86//! ### The `TestTermination` Trait
87//! 
88//! All your tests' return type must implement `TestTermination`. It's a simple trait that only has
89//! one method, `success() -> bool`, which returns whether the test has failed or not. There are
90//! some provided default implementations, but you're free to implement yours if the default
91//! options do not fit your use case.
92//! 
93//! #### Default Implementations
94//! 
95//! The trait is implemented by default for:
96//! 
97//! - `Result<T: TestTermination, E>`: This'll fail in case of an error, otherwise run `.success()`
98//!     for the returned value and return it.
99//! - `Option<T: TestTermination>`: This'll fail if `None`, otherwise run `.success()` for the
100//!     returned value and return it.
101//! - `()`: This will always return true.
102//! 
103//! #### Example
104//! 
105//! ```
106//! use testify::TestTermination;
107//! 
108//! // This is how the trait is implemented for this type internally.
109//! impl<T: TestTermination, E> TestTermination for Result<T, E> {
110//!     fn success(&self) -> bool {
111//!         match self {
112//!             Ok(inner) => inner.success(),
113//!             Err(_) => false
114//!         }
115//!     }
116//! }
117//! ```
118//! 
119//! ## The `#[testify::setup]` and `#[testify::cleanup]` Macros
120//! 
121//! These two macros allow you to set up the test environment before the execution of the tests,
122//! and to clean it up after the tests have passed.
123//! 
124//! ### Example
125//! 
126//! ```
127//! #[testify::main]
128//! fn main() {}
129//! 
130//! #[testify::test]
131//! async fn test_db() {
132//!     /* CODE THAT REQUIRES A DB */
133//! }
134//! 
135//! #[testify::setup]
136//! async fn setup() {
137//!     backup_dev_db_and_setup_test_one().await;
138//! }
139//! 
140//! #[testify::cleanup]
141//! async fn cleanup() {
142//!     destroy_test_db_and_restore_dev_db_backup().await;
143//! }
144//! ```
145//! 
146//! There's no need to have both a setup and a cleanup function either. You may use them
147//! individually. Both `setup` and `cleanup` functions support both sync and async (with the
148//! `async-tokio` feature enabled).
149//! 
150//! ## Using `cargo testify`
151//! 
152//! Tests are run using the testify command `cargo testify-rs`. It's a command line tool that allows
153//! you to configure the way in which your tests are run. In case you haven't installed it yet, run
154//! `cargo install testify` to set it up.
155//! 
156//! ```
157//! $ cargo testify --help
158//! ```
159//! 
160//! ### Filtering by Name
161//! 
162//! The default `cargo test` command allows you to filter your tests by a substring of the test's
163//! name. Testify goes a bit further by allowing you to use glob pattern matching to filter by
164//! name.
165//! 
166//! ```
167//! $ cargo testify hello*
168//! ```
169//! 
170//! ### Filtering by Tag
171//! 
172//! You can also filter by the tags you've set in your tests by passing the `--tag` argument to the
173//! `cargo testify` command.
174//! 
175//! ```
176//! // Both --tag and -t do the same
177//! $ cargo testify --tag auth -t api
178//! ```
179//! 
180//! You can also exclude tags by passing the `--exclude-tag` argument:
181//! 
182//! ```
183//! $ cargo testify --exclude-tag db
184//! // -e for the shortcut
185//! ```
186//! 
187//! ### Fast Failing
188//! 
189//! If you only care about whether all tests pass or not, you can pass the `--fail-fast` argument.
190//! This'll stop testing on the first test that fails. You'll see a `Failed! Aborted.` next to the
191//! failing test, in case there's any.
192
193#[doc(hidden)]
194pub use testify_core::*;
195
196pub use testify_macros::*;
197
198#[doc(hidden)]
199pub use ctor;