Skip to content

Commit

Permalink
#32 Moved crate doc from inner crate to rstest
Browse files Browse the repository at this point in the history
  • Loading branch information
Michele d'Amico committed Apr 5, 2022
1 parent 13bd859 commit b30b585
Show file tree
Hide file tree
Showing 2 changed files with 229 additions and 229 deletions.
229 changes: 0 additions & 229 deletions rstest_macros/src/lib.rs
@@ -1,232 +1,3 @@
//! This crate will help you to write simpler tests by leveraging a software testing concept called
//! [test fixtures](https://en.wikipedia.org/wiki/Test_fixture#Software). A fixture is something
//! that you can use in your tests to encapsulate a test's dependencies.
//!
//! The general idea is to have smaller tests that only describe the thing you're testing while you
//! hide the auxiliary utilities your tests make use of somewhere else.
//! For instance, if you have an application that has many tests with users, shopping baskets, and
//! products, you'd have to create a user, a shopping basket, and product every single time in
//! every test which becomes unwieldy quickly. In order to cut down on that repetition, you can
//! instead use fixtures to declare that you need those objects for your function and the fixtures
//! will take care of creating those by themselves. Focus on the important stuff in your tests!
//!
//! In `rstest` a fixture is a function that can return any kind of valid Rust type. This
//! effectively means that your fixtures are not limited by the kind of data they can return.
//! A test can consume an arbitrary number of fixtures at the same time.
//!
//! ## What
//!
//! The `rstest` crate defines the following procedural macros:
//!
//! - [`[rstest]`](macro@rstest): Declare that a test or a group of tests that may take
//! [fixtures](attr.rstest.html#injecting-fixtures),
//! [input table](attr.rstest.html#test-parametrized-cases) or
//! [list of values](attr.rstest.html#values-lists).
//! - [`[fixture]`](macro@fixture): To mark a function as a fixture.
//!
//! ## Why
//!
//! Very often in Rust we write tests like this
//!
//! ```
//! #[test]
//! fn should_process_two_users() {
//! let mut repository = create_repository();
//! repository.add("Bob", 21);
//! repository.add("Alice", 22);
//!
//! let processor = string_processor();
//! processor.send_all(&repository, "Good Morning");
//!
//! assert_eq!(2, processor.output.find("Good Morning").count());
//! assert!(processor.output.contains("Bob"));
//! assert!(processor.output.contains("Alice"));
//! }
//! ```
//!
//! By making use of [`[rstest]`](macro@rstest) we can isolate the dependencies `empty_repository` and
//! `string_processor` by passing them as fixtures:
//!
//! ```
//! # use rstest::*;
//! #[rstest]
//! fn should_process_two_users(mut empty_repository: impl Repository,
//! string_processor: FakeProcessor) {
//! empty_repository.add("Bob", 21);
//! empty_repository.add("Alice", 22);
//!
//! string_processor.send_all("Good Morning");
//!
//! assert_eq!(2, string_processor.output.find("Good Morning").count());
//! assert!(string_processor.output.contains("Bob"));
//! assert!(string_processor.output.contains("Alice"));
//! }
//! ```
//!
//! ... or if you use `"Alice"` and `"Bob"` in other tests, you can isolate `alice_and_bob` fixture
//! and use it directly:
//!
//! ```
//! # use rstest::*;
//! # trait Repository { fn add(&mut self, name: &str, age: u8); }
//! # struct Rep;
//! # impl Repository for Rep { fn add(&mut self, name: &str, age: u8) {} }
//! # #[fixture]
//! # fn empty_repository() -> Rep {
//! # Rep
//! # }
//! #[fixture]
//! fn alice_and_bob(mut empty_repository: impl Repository) -> impl Repository {
//! empty_repository.add("Bob", 21);
//! empty_repository.add("Alice", 22);
//! empty_repository
//! }
//!
//! #[rstest]
//! fn should_process_two_users(alice_and_bob: impl Repository,
//! string_processor: FakeProcessor) {
//! string_processor.send_all("Good Morning");
//!
//! assert_eq!(2, string_processor.output.find("Good Morning").count());
//! assert!(string_processor.output.contains("Bob"));
//! assert!(string_processor.output.contains("Alice"));
//! }
//! ```
//!
//! ## Injecting fixtures as function arguments
//!
//! `rstest` functions can receive fixtures by using them as input arguments.
//! A function decorated with [`[rstest]`](attr.rstest.html#injecting-fixtures)
//! will resolve each argument name by call the fixture function.
//! Fixtures should be annotated with the [`[fixture]`](macro@fixture) attribute.
//!
//! Fixtures will be resolved like function calls by following the standard resolution rules.
//! Therefore, an identically named fixture can be use in different context.
//!
//! ```
//! # use rstest::*;
//! # trait Repository { }
//! # #[derive(Default)]
//! # struct DataSet {}
//! # impl Repository for DataSet { }
//! mod empty_cases {
//! # use rstest::*;
//! # trait Repository { }
//! # #[derive(Default)]
//! # struct DataSet {}
//! # impl Repository for DataSet { }
//! use super::*;
//!
//! #[fixture]
//! fn repository() -> impl Repository {
//! DataSet::default()
//! }
//!
//! #[rstest]
//! fn should_do_nothing(repository: impl Repository) {
//! //.. test impl ..
//! }
//! }
//!
//! mod non_trivial_case {
//! # use rstest::*;
//! # trait Repository { }
//! # #[derive(Default)]
//! # struct DataSet {}
//! # impl Repository for DataSet { }
//! use super::*;
//!
//! #[fixture]
//! fn repository() -> impl Repository {
//! let mut ds = DataSet::default();
//! // Fill your dataset with interesting case
//! ds
//! }
//!
//! #[rstest]
//! fn should_notify_all_entries(repository: impl Repository) {
//! //.. test impl ..
//! }
//! }
//!
//! ```
//!
//! Last but not least, fixtures can be injected like we saw in `alice_and_bob` example.
//!
//! ## Creating parametrized tests
//!
//! You can use also [`[rstest]`](attr.rstest.html#test-parametrized-cases) to create
//! simple table-based tests. Let's see the classic Fibonacci example:
//!
//! ```
//! use rstest::rstest;
//!
//! #[rstest]
//! #[case(0, 0)]
//! #[case(1, 1)]
//! #[case(2, 1)]
//! #[case(3, 2)]
//! #[case(4, 3)]
//! #[case(5, 5)]
//! #[case(6, 8)]
//! fn fibonacci_test(#[case] input: u32,#[case] expected: u32) {
//! assert_eq!(expected, fibonacci(input))
//! }
//!
//! fn fibonacci(input: u32) -> u32 {
//! match input {
//! 0 => 0,
//! 1 => 1,
//! n => fibonacci(n - 2) + fibonacci(n - 1)
//! }
//! }
//! ```
//! This will generate a bunch of tests, one for every `#[case(a, b)]`.
//!
//! ## Creating a test for each combinations of given values
//!
//! In some cases you need to test your code for each combinations of some input values. In this
//! cases [`[rstest]`](attr.rstest.html#values-lists) give you the ability to define a list
//! of values (rust expressions) to use for an arguments.
//!
//! ```
//! # use rstest::rstest;
//! # #[derive(PartialEq, Debug)]
//! # enum State { Init, Start, Processing, Terminated }
//! # #[derive(PartialEq, Debug)]
//! # enum Event { Error, Fatal }
//! # impl State { fn process(self, event: Event) -> Self { self } }
//!
//! #[rstest]
//! fn should_terminate(
//! #[values(State::Init, State::Start, State::Processing)]
//! state: State,
//! #[values(Event::Error, Event::Fatal)]
//! event: Event
//! ) {
//! assert_eq!(State::Terminated, state.process(event))
//! }
//! ```
//!
//! This will generate a test for each combination of `state` and `event`.
//!
//! ## Magic Conversion
//!
//! If you need a value where its type implement `FromStr()` trait you
//! can use a literal string to build it.
//!
//! ```
//! # use rstest::rstest;
//! # use std::net::SocketAddr;
//! #[rstest]
//! #[case("1.2.3.4:8080", 8080)]
//! #[case("127.0.0.1:9000", 9000)]
//! fn check_port(#[case] addr: SocketAddr, #[case] expected: u16) {
//! assert_eq!(expected, addr.port());
//! }
//! ```
//! You can use this feature also in value list and in fixture default value.

#![cfg_attr(use_proc_macro_diagnostic, feature(proc_macro_diagnostic))]
extern crate proc_macro;

Expand Down

0 comments on commit b30b585

Please sign in to comment.