An implementation of the Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.
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 fullImplement World trait and describe steps:
use std::time::Duration;
use cucumber::{World as _, given, then, when};
use tokio::time::sleep;
#[derive(Debug, Default, cucumber::World)]
struct World {
user: Option<String>,
capacity: usize,
}
#[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 libtestFor more examples check out the Book (current | edge).
Cucumber DataTables allow you to pass structured data to your steps. This crate provides rich support for DataTables through the DataTable type:
You can receive DataTables directly as step parameters:
use cucumber::{given, DataTable, World};
#[derive(Debug, Default, World)]
struct MyWorld {
products: Vec<Product>,
}
#[derive(Debug)]
struct Product {
name: String,
price: f64,
}
#[given("the following products:")]
fn load_products(world: &mut MyWorld, table: DataTable) {
// Access rows with headers
for row in table.rows_with_header().skip(1) {
world.products.push(Product {
name: row["name"].to_string(),
price: row["price"].parse().unwrap(),
});
}
}DataTables can also be optional in your steps:
#[given("a product")]
fn create_product(world: &mut MyWorld, table: Option<DataTable>) {
if let Some(table) = table {
// Use provided data
let row = table.rows().nth(1).unwrap();
world.products.push(Product {
name: row[0].to_string(),
price: row[1].parse().unwrap(),
});
} else {
// Use defaults when no table provided
world.products.push(Product {
name: "Default".to_string(),
price: 0.0,
});
}
}The DataTable type provides multiple ways to access your data:
// Access as rows
for row in table.rows() {
println!("{:?}", row);
}
// Access with headers as HashMap
for row in table.rows_with_header().skip(1) {
println!("{} costs {}", row["name"], row["price"]);
}
// Transpose the table
let transposed = table.transpose();
// Access specific cells
if let Some(cell) = table.cell(1, 0) {
println!("Cell value: {}", cell);
}
// Get column values
let names: Vec<String> = table.column(0)
.map(|s| s.to_string())
.collect();Feature: Product Management
Scenario: Loading products
Given the following products:
| name | price |
| Apple | 1.20 |
| Banana | 0.50 |
| Orange | 0.80 |
When I calculate the total
Then the total should be 2.50macros(default): Enables step attributes and auto-wiring.timestamps: Enables timestamps collecting for all Cucumber events.output-json(impliestimestamps): Enables support for outputting in Cucumber JSON format.output-junit(impliestimestamps): Enables support for outputting JUnit XML report.libtest(impliestimestamps): Enables compatibility with Rustlibtest's JSON output format. Useful for IntelliJ Rust plugin integration.tracing: Enables integration withtracingcrate.
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.
Scenario Outlineis treated the same asOutlineorExamplein the parser (gherkin/#19).
This project is licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
