#cucumber #testing #bdd #atdd #async

cucumber

Cucumber testing framework for Rust, with async support. Fully native, no external test runners or dependencies.

20 releases (6 breaking)

Uses new Rust 2021

0.13.0 Mar 29, 2022
0.12.0 Feb 10, 2022
0.11.0-rc.1 Dec 28, 2021
0.10.2 Nov 3, 2021
0.1.0 Mar 29, 2016

#17 in Testing

Download history 4101/week @ 2022-04-22 4461/week @ 2022-04-29 5011/week @ 2022-05-06 5012/week @ 2022-05-13 4403/week @ 2022-05-20 3445/week @ 2022-05-27 6323/week @ 2022-06-03 5049/week @ 2022-06-10 5997/week @ 2022-06-17 2876/week @ 2022-06-24 4177/week @ 2022-07-01 3776/week @ 2022-07-08 3436/week @ 2022-07-15 3325/week @ 2022-07-22 4147/week @ 2022-07-29 3624/week @ 2022-08-05

15,322 downloads per month
Used in fewer than 7 crates

MIT/Apache

355KB
6K SLoC

Cucumber testing framework for Rust

Documentation CI Rust 1.57+ Unsafe Forbidden

An implementation of the Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.

Usage

Describe testing scenarios in .feature files:

Feature: Eating too much cucumbers may not be good for you
    
  Scenario: Eating a few isn't a problem
    Given Alice is hungry
    When she eats 3 cucumbers
    Then she is full

Implement World trait and describe steps:

use std::{convert::Infallible, time::Duration};

use async_trait::async_trait;
use cucumber::{given, then, when, WorldInit};
use tokio::time::sleep;

#[derive(Debug, WorldInit)]
struct World {
    user: Option<String>,
    capacity: usize,
}

#[async_trait(?Send)]
impl cucumber::World for World {
    type Error = Infallible;

    async fn new() -> Result<Self, Self::Error> {
        Ok(Self { user: None, capacity: 0 })
    }
}

#[given(expr = "{word} is hungry")] // Cucumber Expression
async fn someone_is_hungry(w: &mut World, user: String) {
    sleep(Duration::from_secs(2)).await;
    
    w.user = Some(user);
}

#[when(regex = r"^(?:he|she|they) eats? (\d+) cucumbers?$")]
async fn eat_cucumbers(w: &mut World, count: usize) {
    sleep(Duration::from_secs(2)).await;

    w.capacity += count;
    
    assert!(w.capacity < 4, "{} exploded!", w.user.as_ref().unwrap());
}

#[then("she is full")]
async fn is_full(w: &mut World) {
    sleep(Duration::from_secs(2)).await;

    assert_eq!(w.capacity, 3, "{} isn't full!", w.user.as_ref().unwrap());
}

#[tokio::main]
async fn main() {
    World::run("tests/features/readme").await;
}

Add test to Cargo.toml:

[[test]]
name = "readme"
harness = false  # allows Cucumber to print output instead of libtest

For more examples check out the Book (current | edge).

Cargo features

  • macros (default): Enables step attributes and auto-wiring.
  • timestamps: Enables timestamps collecting for all Cucumber events.
  • output-json (implies timestamps): Enables support for outputting in Cucumber JSON format.
  • output-junit (implies timestamps): Enables support for outputting JUnit XML report.

Supporting crates

The full gamut of Cucumber's Gherkin language is implemented by the gherkin crate. Most features of the Gherkin language are parsed already and accessible via the relevant structs.

Known issues

  • Scenario Outline is treated the same as Outline or Example in the parser (gherkin/#19).

License

This project is licensed under either of

at your option.

Dependencies

~7–14MB
~253K SLoC