BDD in Rust: Writing Living Code with Cucumber and Specs

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why BDD in Rust is Not About Boring Tests

\n\n

Imagine: you are writing a high-load service in Rust. The code is safe, fast, but when the product reaches the client, they say: "I thought the button should work differently." Sound familiar? The classic gap between code and expectations. This is where BDD (Behaviour-Driven Development) comes to the rescue — a methodology that translates business requirements into a language understandable by both the manager and the Rust compiler.

\n\n

In this article, we will explore how to implement BDD in Rust in practice. You will learn how to write scenarios in human language (Gherkin), automate them using cucumber and specs, and why this makes your code not only reliable but also transparent for the entire team. No fluff — only living code and real examples.

\n\n

What is BDD and Why Rust is Ideal for It

\n\n

Behaviour-Driven Development is an evolution of TDD. While TDD focuses on "how to test code," BDD answers the question "what behavior do we want to see." You write scenarios in the Gherkin language (Given-When-Then), which serve as both tests and documentation.

\n\n

Rust is a language that loves strictness and predictability. BDD in Rust provides:

\n
    \n
  • Self-documenting code — any developer reads the scenario and understands the business logic.
  • \n
  • Type-level safety — the compiler checks that your steps match the structure.
  • \n
  • Parallel execution — BDD tests in Rust run fast thanks to async and multithreading.
  • \n
\n\n

When is BDD in Rust Especially Useful?

\n
    \n
  • API services with clear contracts (REST, GraphQL).
  • \n
  • Systems with business rules (finance, logistics, games).
  • \n
  • Microservices where integration between components is important.
  • \n
\n\n

Tools for BDD in Rust: Cucumber and Specs

\n\n

The Rust ecosystem offers two main approaches:

\n\n

1. cucumber — the classic BDD framework

\n

Allows you to write scenarios in Gherkin (.feature files) and bind them to Rust code. Supports async, custom macros, and reports.

\n\n

2. specs — a lightweight and fast alternative

\n

Does not require Gherkin files — scenarios are written directly in Rust using macros. Ideal if you don't want to drag in a separate parser.

\n\n

We will focus on cucumber, as it provides maximum flexibility and conforms to the BDD standard.

\n\n

Writing Your First BDD Scenario in Rust

\n\n

Let's create a simple discount calculator. Business rule: if the purchase amount is greater than 1000 rubles, the discount is 10%. Otherwise — 0%.

\n\n

Step 1. Install Dependencies

\n

Add to Cargo.toml:

\n
[dev-dependencies]\ncucumber = "0.20"\ntokio = { version = "1", features = ["full"] }\nasync-trait = "0.1"\n
\n\n

Step 2. Create a Feature File

\n

File tests/features/discount.feature:

\n
Feature: Discount Calculation\n  As a customer\n  I want to get a discount on a large purchase\n  So that I can save money\n\n  Scenario: Purchase over 1000 rubles\n    Given the purchase amount is "1500"\n    When I request the discount calculation\n    Then the discount amount should be "150"\n\n  Scenario: Purchase under 1000 rubles\n    Given the purchase amount is "500"\n    When I request the discount calculation\n    Then the discount amount should be "0"\n
\n\n

Step 3. Write Steps in Rust

\n

Create tests/steps/discount_steps.rs:

\n
use cucumber::{given, then, when, World};\nuse async_trait::async_trait;\n\n#[derive(Debug, Default)]\nstruct DiscountWorld {\n    purchase_amount: f64,\n    discount: f64,\n}\n\n#[async_trait(?Send)]\nimpl World for DiscountWorld {\n    // Empty implementation for simplicity\n    async fn new() -> Self {\n        Self::d                

Blogs

Book Recommendations