cucumber_rust

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

10 releases (4 breaking)

0.4.0 Aug 8, 2018
0.3.4 Aug 1, 2018
0.3.3 Jul 4, 2018
0.2.1 Jun 28, 2018
0.0.1 Jun 17, 2018

#45 in Testing

Download history 37/week @ 2018-06-21 42/week @ 2018-06-28 65/week @ 2018-07-05 14/week @ 2018-07-12 48/week @ 2018-07-19 18/week @ 2018-07-26 42/week @ 2018-08-02 86/week @ 2018-08-09 35/week @ 2018-08-16 13/week @ 2018-08-23 6/week @ 2018-08-30 22/week @ 2018-09-06 9/week @ 2018-09-13

113 downloads per month
Used in 1 crate

MIT/Apache

49KB
1K SLoC

cucumber-rust

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

Usage

Create a directory called tests/ in your project root and create a test target of your choice. In this example we will name it cucumber.rs.

Add this to your Cargo.toml:

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

[dev-dependencies]
cucumber_rust = "^0.5.0"

If using stable Rust, you need to disable the nightly feature:

cucumber_rust = { version = "^0.5.0", default-features = false }

Create a directory called features/ and put a feature file in it named something like example.feature. It might look like:

Feature: Example feature

  Scenario: An example scenario
    Given I am trying out Cucumber
    When I consider what I am doing
    Then I am interested in ATDD
    And we can implement rules with regex

And here's an example of implementing those steps using our tests/cucumber.rs file:

#[macro_use]
extern crate cucumber_rust;

pub struct MyWorld {
    // You can use this struct for mutable context in scenarios.
    foo: String
}

impl cucumber_rust::World for MyWorld {}
impl std::default::Default for MyWorld {
    fn default() -> MyWorld {
        // This function is called every time a new scenario is started
        MyWorld { 
            foo: "a default string".to_string()
        }
    }
}

mod example_steps {
    // Any type that implements cucumber_rust::World + Default can be the world
    steps!(::MyWorld => {
        given "I am trying out Cucumber" |world, step| {
            world.foo = "Some string".to_string();
            // Set up your context in given steps
        };

        when "I consider what I am doing" |world, step| {
            // Take actions
            let new_string = format!("{}.", &world.foo);
            world.foo = new_string;
        };

        then "I am interested in ATDD" |world, step| {
            // Check that the outcomes to be observed have occurred
            assert_eq!(world.foo, "Some string.");
        };

        then regex r"^we can (.*) rules with regex$" |world, matches, step| {
            // And access them as an array
            assert_eq!(matches[1], "implement");
        };

        then regex r"^we can also match (\d+) (.+) types$" (usize, String) |world, num, word, step| {
            // `num` will be of type usize, `word` of type String
            assert_eq!(num, 42);
            assert_eq!(word, "olika");
        };
    });
}

// Declares a before handler function named `a_before_fn`
before!(a_before_fn => |scenario| {

});

// Declares an after handler function named `an_after_fn`
after!(an_after_fn => |scenario| {

});

// A setup function to be called before everything else
fn setup() {
    
}

cucumber! {
    features: "./features", // Path to our feature files
    world: ::MyWorld, // The world needs to be the same for steps and the main cucumber call
    steps: &[
        example_steps::steps // the `steps!` macro creates a `steps` function in a module
    ],
    setup: setup, // Optional; called once before everything
    before: &[
        a_before_fn // Optional; called before each scenario
    ], 
    after: &[
        an_after_fn // Optional; called after each scenario
    ] 
}

The cucumber! creates the main function to be run.

The steps! macro generates a function named steps with all the declared steps in the module it is defined in. Ordinarily you would create something like a steps/ directory to hold your steps modules instead of inline like the given example.

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

License

This project is licensed under either of

at your option.

Dependencies

~7MB
~116K SLoC