-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement test environments and before/after closures #30
Merged
Merged
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
2c466e9
Add support for test context environments
regexident f69294c
Move environment into Runner (changing strategy from BFS to DFS in PS…
regexident b25a374
Add support for `before` and `after` (and variants) closures
regexident f8be924
Clean up project structure
regexident 5a10889
Make the whole thing parallel in execution.
regexident f0b1aa6
Make runner work with multiple suites, remove unnecessary lifetimes, …
regexident 020d2b2
Rustfmt the files + move runner::Configuration in its own module
twickham 95812d3
move Context modules in a directory
twickham e67b7f4
cargo fmt
twickham 6feb165
Merge pull request #32 from mackwic/extract_context_to_module_dir
mackwic 4e7b0c3
Extract private method and rename inner variables
twickham 1c08f99
remove useless `_with` methods in Runner
twickham a54bbd6
Remove need for `rayon::initialize`
regexident 091cfa5
Remove unused/commented code from example
regexident 899f4a5
Demote suite/context/example names from `String` to `&’static str`
regexident c96b477
Lots of cleanup, a parallel formatter, and lots more
regexident a32a110
Add convenience macro and example
regexident 40fe66c
Improved README
regexident 8cbc9b4
Fix `.or_exit()`, making it less error prone while we’re at it
regexident 0b37f9a
Refactor Runner simplifying `fn visit()` for `Context<T>`
regexident b55e424
Improve module exports & documentation
regexident eeee79c
Improve `EventHandler` (now called `RunnerObserver`)
regexident 651d84a
Improve documentation for `ExampleReport`
regexident f6b7ea3
Clean up suite/context/example header structs & add tests
regexident c365034
Add default impl for `RunnerObserver` trait
regexident 5b36cc1
Move root environment into Suite
regexident cf21311
cargo fmt
twickham 9fc46f7
Add minimal tests for suite
regexident be79277
Fix indentation of Context tests
regexident d8428fa
Improve imports
regexident 98773f8
Clean up `RunnerObserver`
regexident e6cbc61
Change `RunnerObserver` default impls to stable syntax
regexident 2b2eca3
impl default for configuration runner
twickham 4333c68
first tests of the runner
twickham 7b6cde0
str is simpler than String
twickham 19d9428
add Runner::wrap_each tests
twickham f2f515c
add Runner tests for wrap_all and Drop trait
twickham 9ca53f4
Add first test for impl_visitor_block_for_runner
twickham 09cd99d
Fix macro, allowing passing of expression, not just identifiers
regexident eb546ba
Fix missing new-line in formatter
regexident 6a7401b
Simplify ‘simple’ example
regexident 137be3e
Replace `rspec_run!` macro with function
regexident 2519af8
Some more cleanup
regexident c30782f
Fix test runner::impl_visitor_block_for_runner::it_can_be_called
twickham 8e3ee5e
Add tests for impl_visitor_example_for_runner
twickham 9b9bbbf
Rename ‘Formatter’ to ‘Logger’
regexident 97cab2b
Improve logger, merging serial & parallel logger
regexident 97b2f62
Fix documentation for `rspec::run(…)` function
regexident File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,52 @@ | ||
# Compiled files | ||
*.o | ||
*.so | ||
*.rlib | ||
*.dll | ||
|
||
# Executables | ||
*.exe | ||
# Created by https://www.gitignore.io/api/rust | ||
|
||
### Rust ### | ||
# Generated by Cargo | ||
# will have compiled files and executables | ||
/target/ | ||
|
||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries | ||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock | ||
Cargo.lock | ||
target | ||
Cargo.lock | ||
*.bk | ||
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
|
||
# These are temporary files generated by racer | ||
*.racertmp | ||
|
||
# End of https://www.gitignore.io/api/rust | ||
|
||
# Created by https://www.gitignore.io/api/osx | ||
|
||
### OSX ### | ||
*.DS_Store | ||
.AppleDouble | ||
.LSOverride | ||
|
||
# Icon must end with two \r | ||
Icon | ||
|
||
# Thumbnails | ||
._* | ||
|
||
# Files that might appear in the root of a volume | ||
.DocumentRevisions-V100 | ||
.fseventsd | ||
.Spotlight-V100 | ||
.TemporaryItems | ||
.Trashes | ||
.VolumeIcon.icns | ||
.com.apple.timemachine.donotpresent | ||
|
||
# Directories potentially created on remote AFP share | ||
.AppleDB | ||
.AppleDesktop | ||
Network Trash Folder | ||
Temporary Items | ||
.apdisk | ||
|
||
# End of https://www.gitignore.io/api/osx | ||
.idea/* | ||
*.iml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ rust: | |
- nightly | ||
- beta | ||
- stable | ||
- 1.9.0 | ||
- 1.19.0 | ||
matrix: | ||
allow_failures: | ||
- rust: nightly | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,37 @@ | ||
[package] | ||
name = "rspec" | ||
authors = [ | ||
"Thomas Wickham <mackwic@gmail.com>", | ||
"Vincent Esche <regexident@gmail.com>", | ||
] | ||
description = "Write Rspec-like tests with stable rust" | ||
version = "1.0.0-beta.3" | ||
authors = ["Thomas Wickham <mackwic@gmail.com>"] | ||
license = "MPL-2.0" | ||
homepage = "https://mackwic.github.io/rspec" | ||
repository = "https://github.com/mackwic/rspec" | ||
keywords = [ | ||
"rspec", | ||
"test", | ||
"harness", | ||
"tdd", | ||
"bdd", | ||
] | ||
license = "MPL-2.0" | ||
name = "rspec" | ||
readme = "README.md" | ||
keywords = ["rspec", "test", "harness", "bdd"] | ||
repository = "https://github.com/mackwic/rspec" | ||
version = "1.0.0-beta.4" | ||
|
||
[build-dependencies.clippy] | ||
optional = true | ||
version = "0.0.153" | ||
|
||
[dependencies] | ||
clippy = {version = "0.0", optional = true} | ||
colored = "1.4.0" | ||
derive-new = "0.5.0" | ||
derive_builder = "0.5.0" | ||
rayon = "0.8.2" | ||
|
||
[dependencies.expectest] | ||
optional = true | ||
version = "0.9.1" | ||
|
||
[features] | ||
default = [] | ||
expectest_compat = ["expectest"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ The last stable documentation is available for consultation at | |
[mackwic.github.io/rspec](https://mackwic.github.io/rspec). | ||
|
||
**All rspec releases are garanteed to compile against the latest stable rust and | ||
are tested on all rust versions from the 1.9**. | ||
are tested on all rust versions from the 1.19**. | ||
|
||
## How to use | ||
|
||
|
@@ -32,90 +32,130 @@ extern crate rspec; | |
|
||
You can see complete examples in the [`examples/`](https://github.com/mackwic/rspec/tree/master/examples) directory. | ||
|
||
You can now use rspec in your unit tests, this example will use the `cargo test` | ||
runner: | ||
|
||
```rust | ||
fn add(x: u32, y: u32) -> u64 { | ||
x + y | ||
} | ||
extern crate rspec; | ||
|
||
#[test] | ||
fn test_add() { | ||
rdescribe("add", |ctx| { | ||
ctx.describe("0 <= x + y <= u32::MAX", |ctx| { | ||
ctx.it("2 + 4 = 6", || { | ||
assert_eq!(6, add(2, 4)) | ||
pub fn main() { | ||
// Use a local struct to provide the test contexts with an environment. | ||
// The environment will contain the subject that is to be tested | ||
// along with any additional data you might need during the test run: | ||
#[derive(Clone, Default, Debug)] | ||
struct Environment { | ||
// ... | ||
} | ||
|
||
// `rspec::run(…)` is a convenience wrapper that takes care of setting up | ||
// a runner, logger, configuration and running the test suite for you. | ||
// If you want more direct control, you can manually set up those things, too. | ||
rspec::run(&rspec::describe("rspec, a BDD testing framework", Environment::default(), |ctx| { | ||
// `describe`, or any of its equivalents, opens the root context | ||
// of your test suite. Within you can then either define test examples: | ||
ctx.it("can define top-level tests", |_| true); | ||
|
||
// or make use of sub-contexts to add some structure to your test suite: | ||
ctx.specify("contexts give your tests structure and reduce redundancy", |ctx| { | ||
|
||
ctx.before(|_| { | ||
// Executed once, before any of the contexts/examples is entered. | ||
}); | ||
|
||
ctx.it("4 + 4 = 8", || { | ||
assert_eq!(8, add(4, 4)) | ||
ctx.after(|_| { | ||
// Executed once, after all of the contexts/examples have been exited. | ||
}); | ||
|
||
ctx.specify("rspec can handle results", |ctx| { | ||
ctx.it("passes if the return is_ok()", |_| Ok(()) as Result<(),()>); | ||
ctx.it("failes if the return is_err()", |_| Err(()) as Result<(),()>); | ||
}); | ||
|
||
ctx.describe("rspec can handle bools", |ctx| { | ||
ctx.it("should pass if true", |_| true); | ||
ctx.it("should fail if false", |_| false); | ||
ctx.it("is convenient for comparisons", |_| (42 % 37 + 2) > 3); | ||
}); | ||
|
||
ctx.describe("rspec can handle units", |ctx| { | ||
ctx.it("should pass if the return is ()", |_| {}); | ||
}); | ||
|
||
ctx.describe("rspec can handle panics", |ctx| { | ||
ctx.it("is convenient for asserts", |_| assert_eq!(1, 1)); | ||
}); | ||
}); | ||
|
||
ctx.it("is associative", || { | ||
assert_eq!(add(2, 1), add(1, 2)); | ||
assert_eq!(add(4, 1), add(1, 4)); | ||
assert_eq!(add(4, 5), add(5, 4)); | ||
assert_eq!(add(12, 1), add(1, 12)); | ||
}); | ||
}); | ||
})); // exits the process with a failure code if one of the tests failed. | ||
} | ||
``` | ||
|
||
You can also use rspec in integration tests, this example uses the rspec runner: | ||
### Suites, Contexts & Examples | ||
|
||
```rust | ||
extern crate rspec; | ||
use rspec::context::describe; | ||
use std::io; | ||
rspec provides three variants for each of the structural elements: | ||
|
||
pub fn main() { | ||
let stdout = &mut io::stdout(); | ||
let mut formatter = rspec::formatter::Simple::new(stdout); | ||
let mut runner = describe("rspec is a classic BDD testing", |ctx| { | ||
| | Variant A | Variant B | Variant C | | ||
|-----------|------------|------------|------------| | ||
| Suites: | `suite` | `describe` | `given` | | ||
| Contexts: | `context` | `specify` | `when` | | ||
| Examples: | `example` | `it` | `then` | | ||
|
||
**Note:** While the intended use is to stick to a single variant per test suite | ||
it is possible to freely mix structural elements across variants. | ||
|
||
ctx.it("can define tests", || true); | ||
#### Variant A: `suite`, `context` & `example` | ||
|
||
ctx.describe("rspec use results for tests results", |ctx| { | ||
```rust | ||
runner.run(&rspec::suite("opens a suite", /* environment */, |ctx| { | ||
ctx.context("opens a context", |ctx| { | ||
ctx.example("opens an example", |env| /* test condition */ ); | ||
}); | ||
})); | ||
``` | ||
|
||
ctx.it("passed if the return is_ok()", || Ok(()) as Result<(),()>); | ||
#### Variant B: `describe`, `specify` & `it` | ||
|
||
ctx.it("failed if the return is_err()", || Err(()) as Result<(),()>); | ||
}); | ||
```rust | ||
runner.run(&rspec::describe("opens a suite", /* environment */, |ctx| { | ||
ctx.specify("opens a context", |ctx| { | ||
ctx.it("opens an example", |env| /* test condition */ ); | ||
}); | ||
})); | ||
``` | ||
|
||
ctx.describe("rspec can use bools", |ctx| { | ||
#### Variant C: `given`, `when` & `then` | ||
|
||
ctx.it("should pass if true", || true); | ||
```rust | ||
runner.run(&rspec::given("opens a suite", /* environment */, |ctx| { | ||
ctx.when("opens a context", |ctx| { | ||
ctx.then("opens an example", |env| /* test condition */ ); | ||
}); | ||
})); | ||
``` | ||
|
||
ctx.it("should fail if false", || false); | ||
### Before & After | ||
|
||
ctx.it("is convenient for comparisons", || { | ||
(42 % 37 + 2) > 3 | ||
}) | ||
}); | ||
| | All | Each | | ||
|---------|-----------------------|---------------| | ||
| Before: | `before`/`before_all` | `before_each` | | ||
| After: | `after` /`after_all` | `after_each` | | ||
|
||
ctx.describe("rspec can use units", |ctx| { | ||
#### All | ||
|
||
ctx.it("should pass if the return is ()", || {}); | ||
The "All" variants of before and after blocks are executed once upon | ||
entering (or exiting, respectively) the given context. | ||
|
||
ctx.it("is convenient for asserts", || assert_eq!(1, 1)); | ||
}); | ||
}); | ||
runner.add_event_handler(&mut formatter); | ||
runner.run().unwrap(); | ||
} | ||
#### Each | ||
|
||
``` | ||
`before_each` and `after_each` blocks are executed once before each of the | ||
given context's sub-contexts or examples. | ||
|
||
*Note:* | ||
- `describe` has 4 aliases: `specify`, `context`, `given`, and `when` | ||
- `it` has 2 aliases: `example`, and `then` | ||
### More Examples | ||
|
||
Again, you can see complete examples in the [`examples/`](https://github.com/mackwic/rspec/tree/master/examples) directory. | ||
|
||
## Documentation | ||
|
||
The last stable documentation is available for consultation at | ||
[mackwic.github.io/rspec](https://mackwic.github.io/rspec). | ||
[https://docs.rs/rspec](https://docs.rs/rspec). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the new Readme is quite great ! 👌 |
||
|
||
## Contributions | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
extern crate rspec; | ||
|
||
use std::collections::BTreeSet; | ||
|
||
pub fn main() { | ||
#[derive(Clone, Debug)] | ||
struct Environment { | ||
set: BTreeSet<usize>, | ||
len_before: usize, | ||
} | ||
|
||
let environment = Environment { | ||
set: BTreeSet::new(), | ||
len_before: 0, | ||
}; | ||
|
||
rspec::run(&rspec::given("a BTreeSet", environment, |ctx| { | ||
ctx.when("not having added any items", |ctx| { | ||
ctx.then("it is empty", |env| assert!(env.set.is_empty())); | ||
}); | ||
|
||
ctx.when("adding an new item", |ctx| { | ||
ctx.before_all(|env| { | ||
env.len_before = env.set.len(); | ||
env.set.insert(42); | ||
}); | ||
|
||
ctx.then("it is not empty any more", |env| { | ||
assert!(!env.set.is_empty()); | ||
}); | ||
|
||
ctx.then("its len increases by 1", move |env| { | ||
assert_eq!(env.set.len(), env.len_before + 1); | ||
}); | ||
|
||
ctx.when("adding it again", |ctx| { | ||
ctx.before_all(|env| { | ||
env.len_before = env.set.len(); | ||
env.set.insert(42); | ||
}); | ||
|
||
ctx.then("its len remains the same", move |env| { | ||
assert_eq!(env.set.len(), env.len_before); | ||
}); | ||
}); | ||
}); | ||
|
||
ctx.when("returning to outer context", |ctx| { | ||
ctx.then("it is still empty", |env| assert!(env.set.is_empty())); | ||
}); | ||
|
||
ctx.then("panic!(…) fails", move |_env| { | ||
panic!("Some reason for failure.") | ||
}); | ||
})); | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the Environment is an advanced feature that should not be used by default for every test. Maybe split the example in 2, one really simple, and another that showcase the Environment use ?