Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dzejkop/catchr

A testing framework for Rust inspired by Catch!
https://github.com/dzejkop/catchr

bdd bdd-tests rust rust-crate rust-lang testing testing-framework

Last synced: about 2 months ago
JSON representation

A testing framework for Rust inspired by Catch!

Awesome Lists containing this project

README

        

![Rust](https://github.com/Dzejkop/catchr/workflows/Rust/badge.svg)
[![Crates.io](https://img.shields.io/crates/d/catchr.svg)](https://crates.io/crates/catchr)

# Catchr

_Experimental: Might eat your laundry!_

A testing framework for Rust inspired by [Catch for C++](https://github.com/catchorg/Catch2).

## Quickstart

### Add `catchr = "0.3.0"` to your `Cargo.toml`

### Write tests:

```rust
#[cfg(test)]
mod tests {
catchr::describe! {
section "my tests" {
given "x is equal to 1" {
let mut x = 1;

when "1 is added to x" {
x += 1;

then "x should equal 2" {
assert_eq!(2, x);
}
}

when "2 is added to x" {
x += 2;

then "x should equal 3" {
assert_eq!(3, x);
}
}

// for all code paths
assert!(x >= 2);
}
}
}
}
```

### `cargo test`

```
running 2 tests
test tests::section_my_tests::given_x_is_equal_to_1::when_2_is_added_to_x::then_x_should_equal_3 ... ok
test tests::section_my_tests::given_x_is_equal_to_1::when_1_is_added_to_x::then_x_should_equal_2 ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

## Sections

Each test section consists of a keyword, a description and a body.

```rust
keyword "description" {
// body
}
```

For the moment the following keywords are supported: `section`, `case`, `when`, `then`, `given`.

Sections without any nested section will become test cases. Sections function like scopes - that is statements from the outer section are available in the inner section:

```rust
when "something" {
let x = 1;

then "anything" {
let y = 1;
assert_eq!(x, y);
}

then "whatever" {
assert!(true);
}
}
```

The `let x = 1;` can be used in the `then "anything"` section. But `let y = 1;` from the `then "anything"` section, cannot be used in the `then "whatever"` section.

Furthermore the scoping rules are preserved, so that inner test cases can borrow mutably without violating the borrow checker rules.

Consider the following example:

```rust
case "a" {
let mut tmp = tempfile().unwrap();

case "should write some data" {
let mut writer = BufWriter::new(&mut tmp);
writer.write_all(&[1, 2, 3]).unwrap();
}

tmp.seek(SeekFrom::Start(0)).unwrap();
let bytes_in_tmp_file = tmp.seek(SeekFrom::End(0)).unwrap();

assert_eq!(bytes_in_tmp_file, 3);
}
```

if the test case was expanded without scoping, we'd get

```rust
let mut tmp = tempfile().unwrap();

let mut writer = BufWriter::new(&mut tmp);
writer.write_all(&[1, 2, 3]).unwrap();

tmp.seek(SeekFrom::Start(0)).unwrap();
let bytes_in_tmp_file = tmp.seek(SeekFrom::End(0)).unwrap();

assert_eq!(bytes_in_tmp_file, 3);
```

which fails to compile!

so `catchr` will expand this test case into

```rust
let mut tmp = tempfile().unwrap();

{
let mut writer = BufWriter::new(&mut tmp);
writer.write_all(&[1, 2, 3]).unwrap();
}

tmp.seek(SeekFrom::Start(0)).unwrap();
let bytes_in_tmp_file = tmp.seek(SeekFrom::End(0)).unwrap();

assert_eq!(bytes_in_tmp_file, 3);
```

## Async support

You can also use the `describe_tokio` macro to generate async tests that work with the tokio runtime.
First you need to make sure that you have `tokio` in your dependencies and it has the required features - my recommendation is to use `features = ["full]"`.

Next just write

```rust
catchr::describe_tokio! {
when "Something" {
then "Something" {
// it's possible to `.await` here
assert!(true);
}
}
}
```

## How does it work?

The code from the [**Quickstart**](##Quickstart) section will expand into something like this:

```rust
#[cfg(test)]
mod tests {
mod section_my_tests {
use super::*;

mod given_x_is_equal_to_1 {
use super::*;

mod when_1_is_added_to_x {
use super::*;

#[test]
fn then_x_should_equal_2() {
{
let mut x = 1;
{
x += 1;
{
assert_eq!(2, x);
}
}
assert!(x >= 2);
}
}
}

mod when_2_is_added_to_x {
use super::*;

#[test]
fn then_x_should_equal_3() {
{
let mut x = 1;
{
x += 2;
{
assert_eq!(3, x);
}
}
assert!(x >= 2);
}
}
}
}
}
}
```