rassert

:crab: :question: :exclamation:

Fluent, easy-to-extend testing assertions for Rust.

rassert uses The MIT License. Current crates.io version. Continuous Integration status.

Features

Up and Running

First, add rassert to the dev-dependencies section of your Cargo.toml file:

~~~~TOML [dev-dependencies] rassert = "1" ~~~~

Then simply import the prelude module in your tests:

~~~~Rust

[cfg(test)]

mod tests { use rassert::prelude::*;

#[test]
fn rassert_works() {
    expect!(&true)
        .not()
        .to_be_false()
        .and()
        .to_equal(true)
        .conclude_panic();
}

} ~~~~

Writing Assertions

Expectation Chains

In rassert one can write assertions in the form of expectation chains. Such chains allow for writing multiple expectations against the same expression. There are two so-called entry points with which one can start a chain:

Once a chain is started, one can subsequently call expectations on it, as follows:

~~~~Rust let v = vec![10];

expect!(&v) .tobenonempty() .and() .tocontain(10); ~~~~

Note, that the and() call is not mandatory, as it only serves readability purposes.

Concluding Chains

Since rassert evaluates expectations lazily, a chain like the above one will do nothing. A chain will only assert the specified expectations when concluded:

~~~~Rust // Will panic on a failed expectation. expect!(&true) .tobe(false) .concludepanic();

// Will return Result<(), String> containing the error // message on failure. let res = expect!(&true) .tobe(false) .concluderesult(); ~~~~

Soft Mode

A chain can be put into soft mode by calling soft() prior to concluding the chain:

~~~~Rust let v = vec![10];

expect!(&v) .tocontain(15) .and() .tocontain(20) .soft() .conclude_panic(); ~~~~

Soft chains will not panic/return on the first failure, instead they will run each assertion and present a merged report of every failure that occurred.

Negating Expectations

One can negate a single subsequent expectation using the not() function:

~~~~Rust expect!(&true) .not() .tobefalse() .conclude_panic(); ~~~~

If one wishes to negate additionals expectations, then not() has to be applied again.

Available Expectations

Custom Expectations

Custom expectations can be written as extension traits on the ExpectationChain type, provided by rassert. In what follows, we show how to write custom expectations through an example.

Let's assume, that we want to write an expectation against a custom struct, Pizza:

~~~~Rust

[derive(Debug)]

pub struct Pizza { pub flavor: String } ~~~~

In rassert, expectations are actually structs, following something like a Command pattern. Given, we want to check what flavor of Pizza we have, we can create something as follows:

~~~~Rust use rassert::Expectation;

struct ExpectPizzaFlavor { expected_flavor: String }

impl Expectation for ExpectPizzaFlavor { fn test(&self, actual: &Pizza) -> bool { actual.flavor.eq(&self.expected_flavor) }

fn message(&self, expression: &str, actual: &Pizza) -> String {
    format!("Expected {:?}\n  to have flavor {}\n  but had {}.", expression, self.expected_flavor, actual.flavor)
}

} ~~~~

Implementing the Expectation trait comes with two functions:

Once we got our expectation struct written, we can finally extend the ExpectationChain type:

~~~~Rust use rassert::ExpectationChain;

pub trait PizzaExpectationsExt<'a> { fn tohaveflavor(self, expected: &str) -> ExpectationChain<'a, Pizza>; }

impl<'a> PizzaExpectationsExt for ExpectationChain<'a, Pizza> { fn tohaveflavor(self, expected: &str) -> ExpectationChain<'a, Pizza> { self.expecting(ExpectPizzaFlavor { expectedflavor: expected.toowned() }) } } ~~~~

The most important bits of the above snippet are the following:

Then, using the above expectation is as easy as

~~~~Rust let pizza = Pizza { flavor: "Hawaii".to_owned(), };

expect!(&pizza) .tohaveflavor("Margherita") .conclude_panic(); ~~~~

The built-in expectations of the src/expectations directory also use the above facilities, therefore they serve as a great starting point for writing custom expectations.

License

Licensed under The MIT License