[易学易懂系列|rustlang语言|零基础|快速入门|(29)|实战6:BDD工具cucumber_rust]

Posted gyc567

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[易学易懂系列|rustlang语言|零基础|快速入门|(29)|实战6:BDD工具cucumber_rust]相关的知识,希望对你有一定的参考价值。

[易学易懂系列|rustlang语言|零基础|快速入门|(29)|实战6:BDD工具cucumber_rust]

项目实战

实战6:BDD工具cucumber_rust

今天我们来学习下BDD行为驱动测试工具cucumber_rust。

关于BDD,可以简单看看这些介绍:

https://www.cnblogs.com/superhin/p/11454716.html#bdd%E4%BB%8B%E7%BB%8D

https://www.jianshu.com/p/0389360ac58f

https://www.infoq.cn/article/2011/02/BDD-ATDD

简单来说,BDD是一种更好,更直观的一种测试驱动开发方法 。

它也是TDD的一种。

它也是遵守如下开发流程:

技术图片

我们今天要学习的cucumber_rust,是BDD的rust语言版本:

好吧,我们现在开始。

先用命令创建工程:

cargo new bdd_with_cucumber

然后,我们在文件Cargo.toml加入依赖:

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

[dev-dependencies]
cucumber = { package = "cucumber_rust", version = "^0.6.0" } 

在当前工程目录下创建目录:tests和features,目录结构如下 :

bdd_with_cucumber
├── Cargo.lock
├── Cargo.toml
├── tests
├── features
├── src
│   └── main.rs
└── target
    └── debug
        └── ...

我们在tests目录下,创建文件:cucumber.rs,加入如下代码:

use cucumber::{cucumber, steps, before, after};

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

impl cucumber::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 {
    use cucumber::steps;
    
    // Any type that implements cucumber::World + Default can be the world
    steps!(crate::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");
        };

        then "we can use data tables to provide more parameters" |world, step| {
            let table = step.table().unwrap().clone();

            assert_eq!(table.header, vec!["key", "value"]);

            let expected_keys = table.rows.iter().map(|row| row[0].to_owned()).collect::<Vec<_>>();
            let expected_values = table.rows.iter().map(|row| row[1].to_owned()).collect::<Vec<_>>();

            assert_eq!(expected_keys, vec!["a", "b"]);
            assert_eq!(expected_values, vec!["fizz", "buzz"]);
        };
    });
}

// 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: crate::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
    ] 
}

然后,我们在目录:features下创建文件:example.feature,加入如下代码:

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

然后,我们运行命令:

cargo test --test cucumber

运行结果如下:


Feature: Example feature
 \\?E:code
ustProjectdd_with_cucumber_rustfeaturesexample.feature:1:1

 Scenario: An example scenario
 \\?E:code
ustProjectdd_with_cucumber_rustfeaturesexample.feature:3:15
  ? Given I am trying out Cucumber
 \\?E:code
ustProjectdd_with_cucumber_rustfeaturesexample.feature:4:9
  ? When I consider what I am doing
 \\?E:code
ustProjectdd_with_cucumber_rustfeaturesexample.feature:5:9
  ? Then I am interested in ATDD
 \\?E:code
ustProjectdd_with_cucumber_rustfeaturesexample.feature:6:9
  ? And we can implement rules with regex
 \\?E:code
ustProjectdd_with_cucumber_rustfeaturesexample.feature:7:9

1 features
1 scenarios (1 passed)
4 steps (4 passed)

以上,希望对你有用。

如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust

github地址:https://github.com/gyc567/bdd_with_cucumber_rust/tree/master

https://blog.testlodge.com/what-is-bdd/

https://cucumber.io/

https://www.agilealliance.org/glossary/bdd/

以上是关于[易学易懂系列|rustlang语言|零基础|快速入门|(29)|实战6:BDD工具cucumber_rust]的主要内容,如果未能解决你的问题,请参考以下文章

[易学易懂系列|rustlang语言|零基础|快速入门|]

[易学易懂系列|rustlang语言|零基础|快速入门|(11)]

[易学易懂系列|rustlang语言|零基础|快速入门|(14)]

[易学易懂系列|rustlang语言|零基础|快速入门|(12)]

[易学易懂系列|rustlang语言|零基础|快速入门|(13)]

[易学易懂系列|rustlang语言|零基础|快速入门|(21)|智能指针]