Living Documentation with BDD Features
Living Documentation with BDD Features: A Comprehensive Guide
Version 2.0 — Definitive Standard
Table of Contents
- Introduction
- Core Philosophy
- The Feature Structure
- Features vs Rules vs Scenarios
- Writing Features
- Writing Rules
- Writing Scenarios
- Using Tags
- Organizing Features into Modules
- Language and Vocabulary
- Common Anti-Patterns
- Case Study: Cart Management
- Complete Example
- Quality Checklist
1. Introduction
1.1 What Is Living Documentation?
Living documentation is documentation that:
- Evolves with the system it describes
- Remains accurate because it's verified continuously
- Serves multiple audiences: business stakeholders, developers, testers, and product owners
- Uses business language that everyone can understand
- Drives implementation rather than documenting it after the fact
1.2 Why BDD Features?
BDD (Behavior-Driven Development) features using Gherkin syntax provide:
- Shared understanding across technical and non-technical team members
- Executable specifications that can be automated
- Clear traceability from business requirement to implementation
- Natural language documentation accessible to all stakeholders
- Single source of truth for what the system does
1.3 Who Should Read This?
- Product owners defining requirements
- Business analysts documenting capabilities
- Domain experts contributing knowledge
- Developers implementing features
- QA engineers writing tests
- Anyone responsible for maintaining system documentation
2. Core Philosophy
2.1 Three Fundamental Principles
Features describe capabilities
Rules describe constraints
Scenarios describe examples
This hierarchy must be preserved. Violating it leads to feature sprawl, duplication, and confusion.
2.2 Business-First Thinking
Every statement in a feature file must answer: "What business value does this provide?"
If the answer involves technology, implementation, or how the system is structured internally, it doesn't belong in the feature file.
Feature files document what the business needs, not how the system delivers it.
2.3 Who Are We Writing For?
Feature files serve multiple audiences with one shared language:
- Business stakeholders who define requirements
- Product owners who prioritize work
- Domain experts who understand the business rules
- Developers who implement the capability
- Testers who verify the behavior
- Future team members who need to understand what the system does
If any of these audiences cannot understand a feature file, it's not written correctly.
The key insight: we write features in language that everyone can understand, not in language that requires technical knowledge.
3. The Feature Structure
3.1 Mandatory Components
Every feature file must contain:
Feature: <capability name>
In order to <business value>
As a <primary role>
I need to <capability>
Rule: <constraint description>
Scenario: The one where <something happens>
Given <context>
When <action>
Then <outcome>3.2 Gherkin 6 Syntax
This standard uses Gherkin 6 which introduces:
Rule:keyword for grouping related scenarios- Better semantic organization
- Clearer separation of concerns
3.3 Component Hierarchy
Feature (1)
├── Intent Block (1, mandatory)
└── Rules (1..n)
└── Scenarios (1..n)
├── Given steps (0..n)
├── When step (1, exactly)
└── Then steps (1..n)4. Features vs Rules vs Scenarios
4.1 What Is a Feature?
A Feature is a business capability that delivers value independently.
The Feature Test:
Can a user clearly say: "I can do this now"?
If removing it would remove a meaningful business capability → it's a feature.
Valid Features:
- Submit an order
- Record a customer visit
- Collect a payment
- Plan a daily route
- Approve a credit request
- Perform stock taking
Not Features:
- User can submit orders (permission)
- Orders require approval above limit (rule)
- Customer must be in route plan (constraint)
- Validate order totals (technical concern)
4.2 What Is a Rule?
A Rule is a constraint that must hold when a feature action occurs.
The Rule Test:
Would this be checked at the moment the user performs this action?
If yes → it belongs as a rule in that feature.
Rules typically represent:
- Business policies
- Permissions and authorization
- Configuration settings
- Approval thresholds
- Assignment constraints (customers, products, territories)
- Regulatory requirements
- Validation criteria
Example Rules:
Rule: Orders may only be placed for customers in the active route plan
Rule: Credit orders must satisfy credit and approval policies
Rule: Product prices are determined automatically based on business configuration
Rule: Only authorized users may place orders4.3 What Is a Scenario?
A Scenario is a concrete example demonstrating a rule.
Scenarios are:
- Examples, not exhaustive test cases
- Specific, not abstract or generic
- Independent of other scenarios
- Focused on one observable outcome
Example:
Scenario: The one where the customer is in the active route plan
Given customer "Acme Store" is in today's active route plan
When the order is placed
Then the order is submitted successfully5. Writing Features
5.1 The Feature Intent Block
Every feature begins with a mandatory intent block:
Feature: <capability name>
In order to <business value>
As a <primary role>
I need to <capability>Rules for intent blocks:
- Use business language only — no technical terms
- State value first — why this matters
- Identify one primary role — who needs this
- Describe the capability — what they can do
- No conditions — save those for rules
- No implementation details — focus on business intent
Good Examples:
Feature: Submit an order
In order to record customer purchases
As a sales representative
I need to submit an order for processingFeature: Approve credit orders
In order to control financial risk
As a credit manager
I need to review and approve orders exceeding credit limitsBad Examples:
# ❌ Too technical
Feature: Order API endpoint
In order to save order data to the database
As the system
I need to expose an order creation endpoint
# ❌ Describes a rule, not a capability
Feature: Validate customer credit
In order to prevent bad debt
As the system
I need to check credit limits before accepting orders
# ❌ Too vague
Feature: Orders
As a user
I want to work with orders5.2 Identifying Real Features
Use this decision tree:
Is it a distinct business capability?
├─ YES → Is it independent?
│ ├─ YES → Is removing it meaningful to users?
│ │ ├─ YES → It's a feature ✓
│ │ └─ NO → It's probably a rule
│ └─ NO → It depends on another feature
└─ NO → Is it a permission/policy/config?
└─ YES → It's a rule, not a feature5.3 Feature Granularity
Too coarse:
# ❌ Too broad
Feature: Sales operationsToo fine:
# ❌ These are behaviors within a capability
Feature: Add product to order
Feature: Remove product from order
Feature: Update order quantityJust right:
# ✓ Correct granularity
Feature: Place an order5.4 When Configuration Isn't a Feature
Configuration flags, tenant settings, and feature toggles are never features.
They are rules that constrain features.
Wrong:
Feature: Enable discounts
Feature: Require customer signatures
Feature: Allow partial paymentsRight:
Feature: Place an order
Rule: Discounts may only be applied when allowed by the business
Rule: An order may require additional details before submission
Rule: An order may include payment information6. Writing Rules
6.1 Rule Purpose
Rules explicitly document the constraints and policies that govern a feature.
They answer: "Under what conditions can this action succeed or fail?"
6.2 Rule Formatting
Rule: <what must be true>Characteristics of good rules:
- Describe what, never how
- Use declarative language
- State the constraint clearly
- Avoid implementation details
- Focus on business concepts
6.3 Good Rule Examples
Rule: Orders may only be placed for customers in the active route plan
Rule: Credit orders must satisfy credit and approval policies
Rule: Product prices are determined automatically based on business configuration
Rule: An order consists of one or more order items
Rule: Discounts may only be applied when allowed by the business
Rule: Only authorized users may place orders6.4 Bad Rule Examples
# ❌ Describes implementation
Rule: Check route_plan_id against customer assignments table
# ❌ Too technical
Rule: Validate request payload contains required fields
# ❌ Restates the feature
Rule: Orders can be placed
# ❌ Tautological/redundant
Rule: An order must be valid before submission
# ❌ UI-focused
Rule: The submit button is disabled until form is complete6.5 When to Create a New Rule
Create a new rule when:
- A distinct business policy applies
- A new constraint affects success/failure
- Configuration changes behavior
- Different permissions apply
- Approval workflows differ
Don't create rules for:
- Implementation details
- Technical validations
- UI states
- Every possible edge case
6.6 Rule Organization
Group rules logically by concern:
Feature: Place an order
# Order construction
Rule: An order consists of one or more order items
# Pricing
Rule: Product prices are determined automatically based on business configuration
# Constraints
Rule: Orders may only be placed for customers in the active route plan
# Permissions
Rule: Only authorized users may place orders
# Financial policies
Rule: Credit orders must satisfy credit and approval policies7. Writing Scenarios
7.1 Scenario Purpose
Scenarios provide concrete examples that:
- Demonstrate how rules work in practice
- Show both success and failure paths
- Clarify ambiguous requirements
- Serve as acceptance criteria
- Enable automated testing
7.2 The Friends Episode Notation (Mandatory)
All scenarios must use this format:
Scenario: The one where <something happens>Why this format?
- Forces descriptive, memorable names
- Prevents generic names like "Valid order" or "Test 1"
- Makes scenarios easy to reference in conversation
- Adds a touch of personality while remaining professional
Examples:
Scenario: The one where a product is added to the order
Scenario: The one where the customer is not in the active route plan
Scenario: The one where approval is required for a credit order
Scenario: The one where a discount promotion is applied
Scenario: The one where the same product is added multiple times7.3 Given-When-Then Structure
Every scenario follows this pattern:
Scenario: The one where <something happens>
Given <context and preconditions>
When <one business action>
Then <observable business outcome>Given: Context
Purpose: Establish the world state before the action
What to include:
- Who is performing the action
- What permissions they have
- What business state exists
- Relevant configuration
- Existing data
- Specific values and quantities
Good Examples:
Given customer "Acme Store" has credit limit of 10000.00
Given "Coca Cola 500ml" batch "B123" has 50 cartons in stock
Given the sales representative has price list "Standard Wholesale"
Given a promotion offers 10% discount on "Coca Cola 500ml" with minimum 10 cartons
Given customer "Acme Store" must sell categories "Soft Drinks" and "Water"Bad Examples:
# ❌ Too technical
Given the database contains customer record ID 12345
# ❌ UI-focused
Given the user is on the order creation page
# ❌ Implementation details
Given the OrderService is initialized
# ❌ Too vague
Given a customer with a credit limit
Given a product with stock
Given discounts are configuredWhen: Action
Purpose: Describe one intentional business action
Rules:
- Exactly one action per scenario
- Use business terminology
- Present tense
- Active voice
- Include specific values
Good Examples:
When "Coca Cola 500ml" with quantity 10 cartons is added to the order
When the quantity is changed to 15 cartons
When a 5% discount is applied to the item
When payment of 1000.00 is recorded
When the order is placedBad Examples:
# ❌ Multiple actions
When the product is added and the discount is applied and the order is saved
# ❌ Technical
When the POST request is sent to /api/orders
# ❌ UI-focused
When the user clicks the Submit button
# ❌ Too vague
When a product is added
When the order is processedThen: Outcome
Purpose: Describe observable business outcome with specific, measurable results
What to include:
- Success or failure state
- Changes to business entities
- Side effects visible to users
- Error conditions (in business terms)
- Concrete values and quantities
Good Examples:
Then the order contains "Coca Cola 500ml" with quantity 10 cartons
Then the selling price is 95.00 per carton
Then inventory is reduced to 40 cartons
Then the order is rejected
Then the order is rejected due to insufficient stock
Then the order payment status is "Fully paid"
Then both payments are included in the orderBad Examples:
# ❌ Implementation
Then the order record is inserted into the database
# ❌ UI state
Then the success message is displayed
# ❌ Too vague
Then it works
Then the order is successful
Then the price is correct
Then stock is updated
# ❌ Implementation detail - specific error message wording
Then the error message is "ERR_001: Insufficient inventory"
Then the error displays "Stock validation failed"Note on Error Messages:
Exact error message wording is an implementation detail and should generally be avoided in scenarios. Focus on the business outcome:
❌ Too specific (ties you to exact wording):
Then the error message is "You have 5 cartons of Coca Cola 500ml left in stock"✅ Business outcome (flexible on wording):
Then the order is rejected due to insufficient stockException: Include specific error messages only when:
- The exact wording is a regulatory/compliance requirement
- The message contains critical business information that affects user decisions
- You're documenting a user-facing error that must be precise for support purposes
In those cases, document it as a separate assertion:
Then the order is rejected due to insufficient stock
And the user is informed of the available quantity7.4 Writing Specific, Not Vague Scenarios
The Specificity Principle:
Every scenario should use concrete values, real product names, actual quantities, and specific error messages.
Vague vs Specific Examples:
| ❌ Vague | ✅ Specific |
|---|---|
Given a product with stock | Given "Coca Cola 500ml" batch "B123" has 50 cartons in stock |
When the product is added | When "Coca Cola 500ml" with quantity 10 cartons is added |
Then the correct price is applied | Then the selling price is 95.00 per carton |
Given a customer with a credit limit | Given customer "Acme Store" has credit limit of 10000.00 |
When a discount is applied | When a 5% discount is applied to the item |
Then an error occurs | Then the order is rejected due to insufficient stock |
Given insufficient stock | Given "Coca Cola 500ml" has 5 cartons in stock |
When stock is checked | When "Coca Cola 500ml" with quantity 10 cartons is added to a sale |
Complete Vague vs Specific Scenario:
❌ Vague:
Scenario: The one where stock validation occurs
Given a product with limited stock
When the product is added with high quantity
Then the system rejects it✅ Specific:
Scenario: The one where stock is insufficient
Given "Coca Cola 500ml" batch "B123" has 5 cartons in stock
When "Coca Cola 500ml" batch "B123" with quantity 10 cartons is added to a sale
Then the item is rejected due to insufficient stockWhy Specificity Matters:
- Developers know exactly what to implement - "95.00 per carton" not "the correct price"
- Testers can verify precisely - Check for business outcome, not exact UI text
- Business stakeholders recognize real scenarios - "Acme Store" not "a customer"
- Documentation serves as examples - Can be used in training and support
- Removes ambiguity - No guessing about what "correct" or "valid" means
- Focuses on business behavior - Not tied to UI implementation details
7.5 One Behavior Per Scenario
Each scenario demonstrates exactly one rule or behavior.
Wrong: Multiple behaviors
Scenario: The one where an order is validated and submitted
Given a sales representative is placing an order
When a product is added with an invalid quantity
Then the order is rejected
And when a valid product is added
Then the order is submitted successfullyRight: Separate scenarios
Scenario: The one where an invalid quantity is rejected
Given a sales representative is placing an order
When a product with quantity 0 is added to the order
Then the order is rejected
Scenario: The one where a valid order is submitted
Given a sales representative has added valid products to an order
When the order is placed
Then the order is submitted successfully7.6 Scenario Independence
Each scenario must be:
- Self-contained — doesn't depend on other scenarios
- Runnable in any order — no sequence dependencies
- Isolated — creates its own test data
Wrong:
Scenario: The one where a product is added
When a product is added to the order
Then the order contains one product
Scenario: The one where another product is added
# ❌ Assumes previous scenario ran
When another product is added to the order
Then the order contains two productsRight:
Scenario: The one where a product is added to an empty order
Given a sales representative is placing an order
When a product is added to the order
Then the order contains the product
Scenario: The one where a product is added to an existing order
Given an order already contains one product
When another product is added to the order
Then the order contains two products7.7 Positive and Negative Cases
For each rule, document:
- Happy path — constraint satisfied
- Violation — constraint not satisfied
Example:
Rule: Orders may only be placed for customers in the active route plan
Scenario: The one where customer is in route plan
Given customer "Acme Store" is in today's active route plan
When the order is placed
Then the order is submitted successfully
Scenario: The one where customer is not in route plan
Given customer "Acme Store" is not in today's active route plan
When the order is placed
Then the order is rejected7.8 Configuration Variants
When behavior changes based on configuration, show both states:
Rule: Discounts may only be applied when allowed by the business
Scenario: The one where discounts are allowed
Given discounts are enabled by business configuration
When a discount is applied to an order item
Then the discount is reflected in the order total
Scenario: The one where discounts are not allowed
Given discounts are disabled by business configuration
When a discount is applied to an order item
Then the order is rejected7.9 When to Use Scenario Outlines
Use Scenario Outlines only when:
- The business intent is identical
- Only data values change
- Examples are truly interchangeable
Good use:
Scenario Outline: The one where different UOMs have different prices
Given a product with prices for multiple UOMs
When the product is added with UOM <uom>
Then the price is <price>
Examples:
| uom | price |
| pieces | 10.00 |
| carton | 95.00 |
| pallet | 900.00|Bad use:
# ❌ Different business intents
Scenario Outline: The one where validation occurs
Given <context>
When <action>
Then <result>
Examples:
| context | action | result |
| invalid customer | order placed | rejected |
| no products | order placed | rejected |
| exceeds credit limit | order placed | pending |8. Using Tags
8.1 What Are Tags?
Tags are metadata annotations that can be added to features, rules, or scenarios to:
- Categorize scenarios by business domain, component, or concern
- Filter which scenarios to run in different contexts
- Organize documentation for different audiences
- Track non-functional requirements (performance, security, etc.)
- Manage test execution strategy
Tags are written with the @ symbol and placed on the line before the element they annotate.
@smoke @critical
Scenario: The one where a product is added to an empty order
Given a sales representative is placing an order for customer "Acme Store"
When "Coca Cola 500ml" with quantity 10 cartons is added to the order
Then the order contains "Coca Cola 500ml" with quantity 10 cartons8.2 Tag Placement Rules
Tags can be placed at three levels:
- Feature level — applies to all scenarios in the feature
- Rule level — applies to all scenarios under that rule
- Scenario level — applies only to that specific scenario
@orders @financial
Feature: Place an order
@pricing
Rule: Product prices are determined by price list hierarchy
@smoke @critical
Scenario: The one where customer group price list overrides user price list
Given the sales representative has price list "Standard Wholesale"
When "Coca Cola 500ml" with quantity 1 carton is added
Then the selling price is 90.00 per carton
@edge-case
Scenario: The one where net price is used for configured customers
Given customer "Acme Store" is configured to use net prices
When "Coca Cola 500ml" is added to the order
Then the selling price is 85.00Tag inheritance:
- Scenarios inherit tags from their Rule
- Scenarios inherit tags from their Feature
- A scenario tagged
@smokeunder a feature tagged@orderseffectively has both tags
8.3 Standard Tag Categories
8.3.1 Test Execution Tags
These tags control when and how scenarios are executed:
| Tag | Purpose | Usage |
|---|---|---|
@smoke | Critical path scenarios that must always work | Run before every deployment |
@regression | Full regression suite | Run nightly or before releases |
@acceptance | User acceptance scenarios | Run before client demos |
@integration | Requires multiple systems | Run in integration environment |
@manual | Cannot be automated yet | Excluded from automated runs |
@wip | Work in progress, not ready | Excluded from CI/CD |
@skip | Temporarily disabled | Documented reason required |
Example:
@smoke @critical
Scenario: The one where credit is within limit
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 3000.00
When a credit order totaling 5000.00 is placed
Then the order is submitted successfully
@regression
Scenario: The one where volume discount applies to large order
Given customer "Acme Store" has volume discounts configured
And ordering 100 cartons qualifies for volume pricing
When "Coca Cola 500ml" with quantity 100 cartons is added
Then the discounted price is applied8.3.2 Business Domain Tags
Group scenarios by business capability or domain area:
| Tag | Domain |
|---|---|
@orders | Order placement and management |
@payments | Payment collection and processing |
@inventory | Stock management |
@pricing | Price calculation and special prices |
@promotions | Promotional campaigns |
@credit | Credit management |
@customers | Customer management |
@products | Product catalog |
Example:
@orders @pricing @promotions
Feature: Place an order
@pricing @special-prices
Rule: Special prices apply when minimum quantity is met
Scenario: The one where special price applies
Given customer "Acme Store" has special price for "Coca Cola 500ml"
When "Coca Cola 500ml" with quantity 5 cartons is added
Then the selling price is 92.00 per carton8.3.3 Priority and Risk Tags
Indicate business criticality and risk level:
| Tag | Meaning |
|---|---|
@critical | Business-critical functionality |
@high-priority | Important but not critical |
@low-priority | Nice to have |
@high-risk | Complex or error-prone area |
@compliance | Regulatory or compliance requirement |
Example:
@critical @compliance
Scenario: The one where credit limit must be respected
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 8000.00
When a credit order totaling 5000.00 is placed
Then the order is rejected
And the error message indicates credit limit exceeded8.3.4 Technical Characteristic Tags
Document non-functional requirements:
| Tag | Characteristic |
|---|---|
@performance | Performance-sensitive scenario |
@security | Security-related behavior |
@slow | Takes longer than 5 seconds |
@database | Requires database |
@external-api | Calls external services |
@offline | Must work without network |
Example:
@performance @slow
Scenario: The one where 1000 order items are processed
Given an order with 1000 different products
When promotions are applied to all items
Then the calculation completes within 10 seconds
@security @compliance
Scenario: The one where user without permission cannot place orders
Given the sales representative does not have "place orders" permission
When the order is placed
Then the order is rejected due to insufficient permissions8.3.5 Configuration and Environment Tags
Specify when scenarios apply:
| Tag | Environment/Config |
|---|---|
@production | Only relevant in production |
@staging | Only for staging environment |
@feature-flag:discount-approval | Requires specific feature flag |
@role:admin | Only for admin users |
@tenant:enterprise | Enterprise tenant only |
@mobile | Mobile application specific |
@web | Web application specific |
@backend | Backend/API specific |
@offline-capable | Works in offline mode |
Example:
@feature-flag:blanket-agreements @backend
Scenario: The one where blanket agreement price is applied
Given customer "Acme Store" has blanket agreement "BA-2024-001" for "Coca Cola 500ml" at 88.00
And the blanket agreement has remaining balance of 100 cartons
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the selling price is 88.00 per carton
@tenant:premium @role:credit-manager @web
Scenario: The one where credit order requires manager approval
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 8000.00
And credit approval is required for orders exceeding limit
When a credit order totaling 5000.00 is placed
Then the order status is "Pending Approval"
And the credit manager can review the order via web portal
@mobile @offline-capable
Scenario: The one where order is placed without network connectivity
Given the mobile device has no network connectivity
When an order for customer "Acme Store" totaling 1500.00 is placed
Then the order is saved on the device
And the sales representative can continue working
And the order will be submitted when connectivity is restored8.3.6 Platform and Channel Tags
Specify which platform or channel the scenario applies to:
| Tag | Platform/Channel |
|---|---|
@mobile | Mobile application (iOS/Android) |
@mobile:ios | iOS specific |
@mobile:android | Android specific |
@web | Web application |
@backend | Backend services/APIs |
@api | API endpoints |
@desktop | Desktop application |
@ussd | USSD channel |
@pos | Point of sale terminal |
Example:
@mobile @mobile:ios @high-priority
Scenario: The one where barcode scanner captures product
Given a sales representative is on the add product screen
When the barcode scanner is activated
And barcode "7891234567890" is scanned
Then "Coca Cola 500ml" is added to the order
@mobile:android @bug:MOBILE-456 @fixed
Scenario: The one where signature capture works on Android
Given customer signature is required
When the signature pad is displayed on Android device
And the customer signs with their finger
Then the signature is captured successfully
@backend @integration
Scenario: The one where order is received from external system
Given an external system submits an order
When the order data is valid
Then the order is accepted
And order confirmation is returned
@web @desktop
Scenario: The one where manager approves credit order from desktop
Given a credit order is pending approval
And the credit manager is logged into web portal
When the order is reviewed and approved
Then the order status changes to "Approved"
And the sales representative is notified
@mobile @backend @sync
Scenario: The one where mobile syncs completed orders to backend
Given 5 orders were completed on mobile device
And the device has network connectivity
When sync is initiated
Then all 5 orders are transmitted to backend
And mobile receives confirmation for each order
@ussd @limited-input
Scenario: The one where order is placed via USSD menu
Given a sales representative dials the USSD code
When they navigate the menu to place order
And select customer and products
Then the order is submitted
And confirmation is displayed on USSD screen8.4 Tag Naming Conventions
Follow these conventions:
- Use lowercase —
@smokenot@Smokeor@SMOKE - Use hyphens for multi-word tags —
@high-prioritynot@highPriorityor@high_priority - Be descriptive —
@payment-integrationnot@pi - Avoid redundancy — Don't tag a scenario
@order-scenarioin a feature already tagged@orders - Use prefixes for categories —
@role:admin,@feature-flag:new-ui
Good:
@smoke @high-priority @feature-flag:multi-paymentBad:
@SMOKE @highPriority @multiPaymentFeature8.5 Practical Tagging Strategies
8.5.1 Smoke Test Suite
Create a minimal set of critical scenarios:
Feature: Place an order
@smoke @critical
Scenario: The one where a basic order is placed successfully
Given customer "Acme Store" is in today's route plan
And the sales representative has permission to place orders
When "Coca Cola 500ml" with quantity 10 cartons is added
And the order is placed
Then the order is submitted successfully
@smoke @critical
Scenario: The one where stock validation prevents overselling
Given "Coca Cola 500ml" has 5 cartons in stock
When "Coca Cola 500ml" with quantity 10 cartons is added to a sale
Then the item is rejectedRun smoke tests with:
# Only scenarios tagged @smoke
cucumber --tags @smoke
# Smoke tests that are also critical
cucumber --tags "@smoke and @critical"8.5.2 Progressive Test Execution
Build test suites of increasing depth:
@smoke
Scenario: The one where an order is placed
@regression
Scenario: The one where promotions are applied
@regression @edge-case
Scenario: The one where multiple promotions conflict
@regression @edge-case @slow
Scenario: The one where 100 products have promotions calculatedExecution strategy:
- Every commit:
@smoke(2 minutes) - Every merge:
@smoke and @regression(15 minutes) - Nightly:
@regression(1 hour) - Weekly: All scenarios (3 hours)
8.5.3 Feature Flag Management
Document which scenarios require specific features:
@feature-flag:blanket-agreements
Rule: Blanket agreements take highest priority in pricing
Scenario: The one where blanket agreement price is applied
# scenario details
@feature-flag:multi-payment
Rule: Multiple payment modes may be used for a single order
Scenario: The one where cash and M-Pesa are combined
# scenario detailsRun only enabled features:
# Only scenarios for enabled features
cucumber --tags "@feature-flag:blanket-agreements or @feature-flag:multi-payment"
# Exclude disabled features
cucumber --tags "not @feature-flag:disabled-feature"8.5.4 Component-Based Organization
Tag by system component for targeted testing:
@orders @pricing-engine @backend
Scenario: The one where price is calculated from price list
@orders @inventory-service @backend
Scenario: The one where stock is validated
@orders @promotions-engine @backend
Scenario: The one where discount is applied
@orders @payment-gateway @external-api @mobile
Scenario: The one where M-Pesa payment is verified
@orders @barcode-scanner @mobile
Scenario: The one where product is scannedRun component-specific tests:
# Test pricing engine changes
cucumber --tags @pricing-engine
# Test all mobile order scenarios
cucumber --tags "@orders and @mobile"
# Test backend integrations only
cucumber --tags "@backend and @external-api"
# Test mobile-specific features excluding iOS
cucumber --tags "@mobile and not @mobile:ios"8.5.5 Cross-Platform Behavior
Document scenarios that apply to multiple platforms within the main business feature:
@orders @mobile @backend
Feature: Place an order
@mobile @offline-capable
Rule: Orders can be placed without network connectivity
@smoke @critical
Scenario: The one where an order is placed offline
Given the mobile device has no network connectivity
When an order totaling 1500.00 is placed
Then the order is saved on the device
And the order will be submitted when connectivity is restored
@regression
Scenario: The one where offline orders are submitted when online
Given 3 orders were saved offline on mobile device
When network connectivity is restored
Then all 3 orders are submitted to the system
And each order receives confirmation
@mobile:ios @mobile:android
Rule: Orders can be placed on both iOS and Android platforms
@smoke
Scenario: The one where an order is placed on iOS
Given a sales representative is using an iPhone
When an order is placed
Then the order is submitted successfully
@smoke
Scenario: The one where an order is placed on Android
Given a sales representative is using an Android device
When an order is placed
Then the order is submitted successfully8.5.6 Platform-Specific Behavior
When to create platform-specific scenarios:
Only create separate scenarios per platform when:
- Business behavior differs between platforms (not just implementation)
- User experience is fundamentally different (mobile camera vs web upload)
- Different capabilities exist (offline on mobile, bulk operations on web)
Don't create platform-specific scenarios when:
- Same business rule applies across all platforms
- Only technical implementation differs (iOS camera API vs Android camera API)
- Testing platform quirks (use automated tests, not feature documentation)
Example of VALID platform differences (different user experiences):
@mobile @camera
Rule: LPO documentation may be captured via device camera
@mobile
Scenario: The one where LPO photo is captured on mobile
Given LPO documentation is required
And the sales representative is using a mobile device
When a photo of the LPO document is captured
Then the photo is attached to the order
@web @file-upload
Rule: LPO documentation may be uploaded from web
@web
Scenario: The one where LPO document is uploaded from web
Given LPO documentation is required
And the manager is using web portal
When a PDF file "LPO-2024-001.pdf" is uploaded
Then the document is attached to the orderExample of INVALID platform duplication (same business rule):
# ❌ Don't do this - implementation details, not business differences
@mobile:ios
Scenario: The one where LPO photo is captured on iPhone
Given LPO documentation is required
And the sales rep is using an iPhone
When the camera is activated
And a photo of the LPO document is taken
Then the photo is attached to the order
@mobile:android
Scenario: The one where LPO photo is captured on Android
Given LPO documentation is required
And the sales rep is using Android device
When the camera is activated
And a photo of the LPO document is taken
Then the photo is attached to the order
# ✅ Do this instead - one scenario with platform tags
@mobile @camera @mobile:ios @mobile:android
Scenario: The one where LPO photo is captured on mobile
Given LPO documentation is required
When a photo of the LPO document is captured via device camera
Then the photo is attached to the orderThe guiding principle:
Platform should never appear in scenario names or Given/When/Then steps
unless the business behavior actually differs by platform.
Examples of incorrect platform mentions:
# ❌ Wrong - stock validation is same business rule everywhere
Scenario: The one where stock is insufficient on mobile
Given "Coca Cola 500ml" has 5 cartons in stock
When the product is added to a sale on mobile
Then the item is rejected due to insufficient stock
# ❌ Wrong - permission check is same business rule everywhere
Scenario: The one where user lacks permission on mobile
Given the user does not have "place orders" permission
And they are using the mobile app
When they attempt to place an order
Then the order is rejected
# ✅ Correct - platform in tags only, business rule is universal
@mobile @web @backend
Scenario: The one where stock is insufficient
Given "Coca Cola 500ml" has 5 cartons in stock
When the product is added to a sale
Then the item is rejected due to insufficient stockWhen platform SHOULD appear (different business behaviors):
# ✅ Correct - fundamentally different capabilities
@mobile
Scenario: The one where order is placed without network connectivity
Given the mobile device has no network connectivity
When an order is placed
Then the order is saved on the device
# This wouldn't make sense on web - web requires connectivity
# So platform context is part of the business ruleIf the scenarios read identically except for the platform name,
they should be ONE scenario with platform tags,
not separate scenarios.
Use tags for platform targeting, not scenario content:
# Run the same business rule test on different platforms
@mobile @web @backend
Scenario: The one where stock is insufficient
# scenario steps...
# Then run specific platforms:
cucumber --tags @mobile # Test on mobile
cucumber --tags @web # Test on web
cucumber --tags @backend # Test backend APILink scenarios to defect tickets:
@bug:ORD-1234 @fixed
Scenario: The one where decimal quantities caused rounding errors
Given fractional quantities are allowed
When "Coca Cola 500ml" with quantity 10.5 cartons is added
Then the selling price is calculated correctly for 10.5 cartons
@bug:ORD-1235 @wip
Scenario: The one where promotions don't apply to service products
Given "Installation Service" is a service product
When the product qualifies for a promotion
Then the promotion is not applied8.6 Tag Combination with Boolean Logic
Most BDD frameworks support tag expressions:
AND logic:
# Scenarios that are both smoke AND critical
cucumber --tags "@smoke and @critical"OR logic:
# Scenarios that are smoke OR critical
cucumber --tags "@smoke or @critical"NOT logic:
# All scenarios except manual ones
cucumber --tags "not @manual"
# All scenarios except WIP and skipped
cucumber --tags "not @wip and not @skip"Complex expressions:
# Smoke tests OR (critical AND not slow)
cucumber --tags "@smoke or (@critical and not @slow)"
# Orders or payments, but not external APIs
cucumber --tags "(@orders or @payments) and not @external-api"8.7 Tags to Avoid
Don't use tags for:
❌ Scenario numbering: @scenario-1, @scenario-2
- Scenarios should be independently meaningful
❌ Test implementation details: @uses-selenium, @rest-api-test
- Features describe business behavior, not how they're tested
❌ Developer names: @john, @team-a
- Use version control for ownership tracking
❌ Generic placeholders: @todo, @fixme
- Use
@wipwith a comment explaining what's needed
❌ Date-based tags: @sprint-23, @Q4-2024
- Features are timeless; use version control for history
8.8 Documenting Tag Strategy
Create a TAGS.md file in your project:
# Tag Strategy
## Test Execution
- `@smoke` - Critical path, run on every build (< 2 min)
- `@regression` - Full suite, run on merge (< 15 min)
- `@manual` - Not automated, excluded from CI
## Business Domains
- `@orders` - Order placement
- `@payments` - Payment collection
- `@pricing` - Price calculation
- `@promotions` - Promotional campaigns
## Priority
- `@critical` - Business-critical
- `@high-priority` - Important
- `@compliance` - Regulatory requirement
## Feature Flags
- `@feature-flag:<name>` - Requires feature flag
## Running Tests
```bash
# Smoke tests only
npm test -- --tags @smoke
# All orders except manual
npm test -- --tags "@orders and not @manual"
### 8.9 Complete Tagged Example
```gherkin
@orders @financial @critical
Feature: Place an order
In order to sell products to customers
As a sales representative
I need to place an order for a customer
@pricing @smoke @backend
Rule: Product prices are determined by price list hierarchy
@smoke @critical @acceptance
Scenario: The one where customer group price list overrides user price list
Given the sales representative has price list "Standard Wholesale" with price 95.00
And customer "Acme Store" belongs to group "Premium Retailers" with price list "Premium"
And "Coca Cola 500ml" carton costs 90.00 on "Premium"
When "Coca Cola 500ml" with quantity 1 carton is added
Then the selling price is 90.00 per carton
@pricing @feature-flag:blanket-agreements @high-priority @backend
Rule: Blanket agreements take highest priority in pricing
@regression @compliance
Scenario: The one where blanket agreement price is applied
Given customer "Acme Store" has blanket agreement "BA-2024-001" for "Coca Cola 500ml" carton at 88.00
And the blanket agreement has remaining balance of 100 cartons
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the selling price is 88.00 per carton
And blanket agreement "BA-2024-001" is recorded on the order item
@promotions @regression @backend
Rule: Promotions are applied automatically to qualifying orders
@smoke @critical
Scenario: The one where percentage discount promotion applies
Given a promotion offers 10% discount on "Coca Cola 500ml" with minimum 10 cartons
And standard price is 95.00 per carton
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the selling price is 85.50 per carton
And promotion type is "Percentage Discount"
@edge-case @slow @performance @backend
Scenario: The one where promotions are calculated for 100 products
Given an order with 100 different products
And each product qualifies for a different promotion
When all promotions are applied
Then calculation completes within 5 seconds
@inventory @smoke @critical @mobile @backend
Rule: Stock must be sufficient for sales and samples
@smoke @acceptance
Scenario: The one where stock is insufficient
Given "Coca Cola 500ml" batch "B123" has 5 cartons in stock
When "Coca Cola 500ml" batch "B123" with quantity 10 cartons is added to a sale
Then the item is rejected due to insufficient stock
@barcode @mobile @mobile:android @high-priority
Rule: Products may be added via barcode scanning
@smoke @mobile:android
Scenario: The one where barcode scanner captures product on Android
Given a sales representative is placing an order on Android device
When barcode "7891234567890" is scanned
Then "Coca Cola 500ml" is added to the order
And the default quantity is set to 1 carton
@mobile:ios @smoke
Scenario: The one where barcode scanner captures product on iOS
Given a sales representative is placing an order on iPhone
When barcode "7891234567890" is scanned
Then "Coca Cola 500ml" is added to the order
And the default quantity is set to 1 carton
@sync @mobile @backend @integration @critical
Rule: Orders created on mobile must sync to backend
@smoke @critical
Scenario: The one where mobile order syncs to backend
Given an order was completed on mobile device "DEVICE-001"
And the device has network connectivity
When sync is initiated
Then the order is transmitted to backend
And backend returns server order ID
And mobile updates local order with server ID
@offline-capable @mobile @regression
Scenario: The one where orders are queued when offline
Given the mobile device is in offline mode
When an order totaling 1500.00 is completed
Then the order is saved locally
And the order is queued for sync
And the user is notified the order will sync when online
@security @compliance @critical @mobile @backend
Rule: Only authorized users may place orders
@smoke @security
Scenario: The one where user lacks permission
Given the sales representative does not have "place orders" permission
When they attempt to place an order
Then the order is rejected due to insufficient permissions
@credit @compliance @critical @high-risk @backend
Rule: Credit limits must be respected
@smoke @critical @acceptance
Scenario: The one where credit exceeds limit
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 8000.00
When a credit order totaling 5000.00 is placed
Then the order is rejected due to exceeding credit limit
@signature @mobile @compliance
Rule: Customer signature may be captured on mobile devices
@mobile:ios @camera @regression
Scenario: The one where signature is captured on iPhone
Given customer signature is required
And the sales rep is using an iPhone
When the signature pad is displayed
And the customer signs with their finger
Then the signature is captured
And the signature is attached to the order
@mobile:android @camera @regression
Scenario: The one where signature is captured on Android
Given customer signature is required
And the sales rep is using an Android device
When the signature pad is displayed
And the customer signs with their finger
Then the signature is captured
And the signature is attached to the order
@approval @web @desktop @workflow
Rule: Credit orders may require manager approval
@web @critical @compliance
Scenario: The one where manager approves order
Given a credit order is pending approval
And the credit manager reviews the order
When the manager approves the order
Then the order status changes to "Approved"
And the sales representative receives a notification8.11 Tag Minimalism: Avoiding Tag Overload
The Tag Overload Problem:
Too many tags make features harder to read, maintain, and understand. Tags should enhance, not obscure.
8.11.1 The Minimalism Principle
Use the minimum number of tags necessary to achieve your organizational goals.
Signs of tag overload:
# ❌ Tag overload - 12 tags!
@orders @pricing @backend @api @integration @smoke @critical @acceptance @regression @high-priority @compliance @financial
Scenario: The one where customer group price list overrides user price list
Given the sales representative has price list "Standard Wholesale"
When "Coca Cola 500ml" with quantity 1 carton is added
Then the selling price is 90.00 per cartonBetter approach:
# ✅ Minimal tags - only what's necessary
@smoke @critical
Scenario: The one where customer group price list overrides user price list
Given the sales representative has price list "Standard Wholesale"
When "Coca Cola 500ml" with quantity 1 carton is added
Then the selling price is 90.00 per carton8.11.2 Tag Inheritance Strategy
Leverage tag inheritance to avoid repeating tags:
# ❌ Repetitive - every scenario tagged @orders @pricing @backend
@orders @pricing @backend
Feature: Place an order
Rule: Product prices are determined by price list hierarchy
@orders @pricing @backend @smoke
Scenario: The one where price is calculated
@orders @pricing @backend @regression
Scenario: The one where price changes with quantity
# ✅ Inherited - feature-level tags apply to all scenarios
@orders @pricing @backend
Feature: Place an order
Rule: Product prices are determined by price list hierarchy
@smoke
Scenario: The one where price is calculated
@regression
Scenario: The one where price changes with quantityTag inheritance levels:
- Feature level — Broad categorization (domain, platform)
- Rule level — Specific concern within feature
- Scenario level — Execution strategy and specifics
8.11.3 Choose Your Tag Strategy
Option A: Minimal Execution Tags Only
Focus only on what controls test execution:
@orders
Feature: Place an order
Rule: Product prices are determined by price list hierarchy
@smoke
Scenario: The one where customer group price overrides user price
@regression
Scenario: The one where volume discounts applyBenefits:
- Clean, readable
- Easy to maintain
- Focuses on test strategy
When to use: Small teams, simple CI/CD, single platform
Option B: Selective Strategic Tags
Add only tags that serve a clear purpose:
@orders
Feature: Place an order
@backend
Rule: Product prices are determined by price list hierarchy
@smoke @critical
Scenario: The one where customer group price overrides user price
@regression @performance
Scenario: The one where 1000 prices are calculated
@mobile @backend @sync
Rule: Orders created on mobile must sync to backend
@smoke @critical
Scenario: The one where mobile order syncs to backendBenefits:
- Balances readability with organization
- Platform clarity where needed
- Performance tests identified
When to use: Multi-platform systems, medium teams, targeted testing
Option C: Comprehensive Tagging
Use multiple tags for detailed organization:
@orders @financial
Feature: Place an order
@pricing @backend @critical
Rule: Product prices are determined by price list hierarchy
@smoke @acceptance @high-priority
Scenario: The one where customer group price overrides user price
@mobile @backend @sync @integration @critical
Rule: Orders created on mobile must sync to backend
@smoke @critical @offline-capable
Scenario: The one where orders queue when offlineBenefits:
- Maximum flexibility
- Detailed reporting
- Complex filtering
When to use: Large teams, multiple platforms, complex CI/CD, compliance requirements
8.11.4 The Three-Tag Rule
General guideline: Most scenarios should have 3 or fewer scenario-level tags.
@orders @mobile
Feature: Place an order
Rule: Products may be added via barcode scanning
# ✅ Good: 2 scenario-level tags
@smoke @mobile:android
Scenario: The one where barcode scanner captures product
# ⚠️ Acceptable: 3 scenario-level tags
@regression @performance @slow
Scenario: The one where 100 products are scanned
# ❌ Too many: 5+ scenario-level tags
@smoke @critical @acceptance @high-priority @compliance
Scenario: The one where product is addedExceptions: Integration scenarios involving multiple systems may need more tags:
# Acceptable for cross-system scenario
@mobile @backend @payment-gateway @external-api @integration
Scenario: The one where mobile payment syncs to backend and gateway8.11.5 Tag Consolidation Strategies
Strategy 1: Use Composite Tags
Instead of multiple related tags, create composite tags:
# ❌ Before: Too many individual tags
@critical @smoke @acceptance @high-priority
# ✅ After: One composite tag
@p0 # Priority 0 = critical smoke tests
# Or use tag expressions in execution
cucumber --tags "@critical and @smoke"Strategy 2: Infer from Context
Don't tag what's obvious from the feature or rule:
# ❌ Redundant tagging
@orders @pricing
Feature: Place an order
@orders @pricing # ← Redundant, inherited from feature
Rule: Product prices are determined automatically
@orders @pricing # ← Even more redundant
Scenario: The one where price is calculated
# ✅ Clean - tags only what's additional
@orders @pricing
Feature: Place an order
Rule: Product prices are determined automatically
@smoke
Scenario: The one where price is calculatedStrategy 3: Platform Tags at Feature/Rule Level
Put platform tags where the entire rule applies:
# ❌ Repetitive platform tags
Feature: Place an order
Rule: Products may be added via barcode
@mobile @mobile:ios
Scenario: The one where barcode scans on iOS
@mobile @mobile:android
Scenario: The one where barcode scans on Android
# ✅ Better - platform at rule level
Feature: Place an order
@mobile
Rule: Products may be added via barcode
@mobile:ios
Scenario: The one where barcode scans on iOS
@mobile:android
Scenario: The one where barcode scans on Android8.11.6 When to Use Each Tag Type
Always use (at appropriate level):
- Execution strategy:
@smoke,@regression - Platform (if multi-platform):
@mobile,@backend,@web
Use sparingly:
- Priority: Only for truly critical scenarios
- Performance: Only for actual performance tests
- Domain: Only at feature level
Rarely use:
- Technical characteristics: Only when it changes test strategy
- Environment: Only when scenario truly environment-specific
Almost never use at scenario level:
- Business domain (put at feature level)
- Company/team tags (use version control)
- Date-based tags (use version control)
8.11.7 Tag Audit Checklist
Before adding a tag, ask:
- Does this tag serve a specific, documented purpose?
- Would removing this tag make anything harder?
- Is this tag unique enough to be useful for filtering?
- Could this be inherited from feature/rule level?
- Am I duplicating information already in the scenario description?
- Will someone else understand why this tag exists?
If you answer "no" to any of these, reconsider the tag.
8.11.8 Real-World Example: Progressive Refinement
Initial version (tag overload):
@orders @sales @financial @critical @high-priority @backend @api @integration @pricing
Feature: Place an order
@orders @pricing @backend @critical @smoke @acceptance @regression
Rule: Product prices are determined automatically
@orders @pricing @backend @critical @smoke @acceptance @p0 @happy-path
Scenario: The one where customer group price overrides user priceAfter refinement (minimal and clear):
@orders @backend
Feature: Place an order
Rule: Product prices are determined automatically
@smoke @critical
Scenario: The one where customer group price overrides user priceWhat was removed and why:
@sales,@financial— Too generic, covered by@orders@high-priority— Redundant with@critical@api,@integration— Implementation details@acceptance,@regression—@smokeimplies these@pricing— Obvious from rule name@p0,@happy-path— Covered by@criticaland@smoke
8.11.9 Team Agreement Template
Create a TAG_POLICY.md:
# Tag Policy
## Our Approach
We use **Option B: Selective Strategic Tags** - minimal tags with clear purpose.
## Mandatory Tags
- Every scenario: One execution tag (`@smoke`, `@regression`, or `@manual`)
- Multi-platform features: Platform tag at feature or rule level
## Optional Tags
- `@critical` - Only for business-critical scenarios (< 10% of scenarios)
- `@slow` - Only for tests taking > 10 seconds
- `@external-api` - Only when calling actual external services
## Forbidden Tags
- Never use `@test`, `@scenario`, `@feature` (redundant)
- Never use developer names or team names
- Never use date-based tags
- Never duplicate scenario-level tags already at feature/rule level
## Maximum Tags
- Feature level: 3 tags maximum
- Rule level: 2 tags maximum
- Scenario level: 3 tags maximum (except cross-system integration)
## Review Criteria
- If a PR adds more than 2 new tags, it requires justification
- All tags must be documented in TAGS.md
- Unused tags must be removed quarterly8.11.10 The Golden Rules of Tagging
- Less is more — Start with minimal tags, add only when needed
- Inherit, don't repeat — Use feature/rule level tags
- Purpose over pattern — Every tag must serve a documented purpose
- Readable first — Scenarios are documentation; tags are metadata
- Review regularly — Remove unused tags every quarter
Remember:
Tags are organizational tools, not documentation.
If you need many tags to explain what a scenario does,
the scenario description needs improvement, not more tags.
Remember:
- Tags are metadata, not documentation
- Don't rely on tags to explain business rules
- Business stakeholders read scenarios, not tags
- Tags support execution and organization, not understanding
Good: Tags supplement clear scenarios
@smoke @critical
Scenario: The one where credit limit prevents over-extension
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 8000.00
When a credit order totaling 5000.00 is placed
Then the order is rejectedBad: Tags replace clear naming
@credit @limit @validation @negative
Scenario: Test case 1
Given limit 10000
When order 5000
Then rejectedTags enhance organization and execution strategy, but scenarios must stand alone as readable documentation.
9. Organizing Features into Modules
9.1 What Are Modules?
Modules are logical groupings of related features that represent a coherent business domain or subdomain.
As your system grows, organizing features into modules:
- Improves discoverability - easier to find related features
- Supports team organization - teams can own modules
- Enables independent evolution - modules can be versioned separately
- Reflects business structure - mirrors how the business thinks about capabilities
9.2 Module vs Feature vs Rule
Understanding the hierarchy:
Module (Domain Area)
└── Feature (Business Capability)
└── Rule (Constraint)
└── Scenario (Example)Example:
Orders Module
├── Place an order (Feature)
│ ├── Stock must be sufficient (Rule)
│ ├── Prices are determined automatically (Rule)
│ └── Credit limits must be respected (Rule)
├── Approve credit orders (Feature)
│ ├── Only managers can approve (Rule)
│ └── Approval history is recorded (Rule)
└── Cancel an order (Feature)
└── Only pending orders can be cancelled (Rule)9.3 Identifying Modules
Ask: "What major business domains exist in our system?"
Good modules (business domains):
- Orders
- Payments
- Inventory
- Customers
- Products
- Pricing
- Promotions
- Route Planning
- Reporting
Not modules (too granular):
- ❌ Order Validation (part of Orders)
- ❌ Price Calculation (part of Pricing)
- ❌ Stock Checking (part of Inventory)
Not modules (too broad):
- ❌ Sales (too vague - contains Orders, Payments, Customers)
- ❌ Operations (too vague - what does this mean?)
9.4 File Structure for Modules
Option A: Flat structure with prefixes
features/
├── orders_place_order.feature
├── orders_approve_order.feature
├── orders_cancel_order.feature
├── payments_collect_payment.feature
├── payments_process_refund.feature
├── inventory_adjust_stock.feature
└── inventory_transfer_stock.featurePros: Simple, all features in one directory Cons: Doesn't scale well beyond 20-30 features
Option B: Module directories (Recommended)
features/
├── orders/
│ ├── place_order.feature
│ ├── approve_credit_order.feature
│ └── cancel_order.feature
├── payments/
│ ├── collect_payment.feature
│ └── process_refund.feature
├── inventory/
│ ├── adjust_stock.feature
│ └── transfer_stock.feature
├── customers/
│ ├── register_customer.feature
│ └── update_customer_details.feature
└── pricing/
├── manage_price_lists.feature
└── apply_special_prices.featurePros: Scalable, clear organization, easy navigation Cons: Requires directory navigation
Option C: Domain-driven directory structure
features/
├── sales/
│ ├── orders/
│ │ ├── place_order.feature
│ │ └── approve_order.feature
│ ├── payments/
│ │ └── collect_payment.feature
│ └── customers/
│ └── register_customer.feature
├── operations/
│ ├── inventory/
│ │ └── adjust_stock.feature
│ └── route_planning/
│ └── plan_route.feature
└── analytics/
└── reporting/
└── generate_sales_report.featurePros: Reflects bounded contexts, supports large systems Cons: Can be over-engineered for smaller systems
9.5 Naming Conventions for Module Files
Use lowercase with underscores:
- ✅
place_order.feature - ✅
collect_payment.feature - ❌
PlaceOrder.feature - ❌
place-order.feature
File name should match feature name:
# File: place_order.feature
Feature: Place an orderKeep names action-oriented:
- ✅
place_order.feature - ✅
collect_payment.feature - ❌
order.feature(too vague) - ❌
order_placement.feature(noun form)
9.6 Module Documentation
Create a README.md in each module directory:
# Orders Module
## Purpose
Manages the complete order lifecycle from creation to fulfillment.
## Features
- **Place an order** - Sales representatives place orders for customers
- **Approve credit order** - Credit managers approve orders exceeding limits
- **Cancel an order** - Cancel pending orders before fulfillment
## Business Rules
- Orders can only be placed for customers in active route plans
- Credit orders require manager approval above credit limit
- Only pending orders can be cancelled
## Key Stakeholders
- Sales representatives
- Credit managers
- Warehouse managers
## Related Modules
- **Payments** - Payment collection for orders
- **Inventory** - Stock validation and reservation
- **Customers** - Customer information and credit limits
## Running Tests
```bash
# All order features
cucumber features/orders
# Smoke tests only
cucumber features/orders --tags @smoke
### 9.7 Cross-Module Dependencies
**Problem:** Features often depend on capabilities from other modules.
**Example:**
```gherkin
# File: orders/place_order.feature
Feature: Place an order
Rule: Payment must be collected for cash sales
Scenario: The one where payment is collected
Given a sales representative is placing a cash sale
When payment of 1000.00 is collected # ← This is from Payments module
Then the order is submitted successfullyGuidelines for cross-module scenarios:
- Keep the scenario in the primary module (where the main action happens)
- Reference other module capabilities naturally (as Given or Then steps)
- Don't duplicate scenarios across modules
- Use tags to indicate dependencies
@orders @payments
Scenario: The one where payment is collected for cash sale
Given a sales representative is placing a cash sale
When payment of 1000.00 is collected
Then the order is submitted successfully
And payment is recorded9.8 Module Tagging Strategy
Tag features at the module level:
@orders
Feature: Place an order
@orders @pricing
Rule: Product prices are determined automatically
@orders @inventory
Rule: Stock must be sufficient for salesBenefits:
- Run all features in a module:
cucumber --tags @orders - Run cross-module scenarios:
cucumber --tags "@orders and @payments" - Identify module dependencies clearly
9.9 Module Size Guidelines
Healthy module size:
- 3-10 features per module
- Each feature: 5-15 rules
- Each rule: 2-5 scenarios
Warning signs of poor modularization:
Module too small:
payments/
└── collect_payment.feature # Only 1 featureSolution: Merge with related module or identify missing features
Module too large:
orders/
├── place_order.feature
├── approve_order.feature
├── cancel_order.feature
├── modify_order.feature
├── track_order.feature
├── archive_order.feature
├── export_order.feature
├── print_order.feature
├── email_order.feature
├── import_order.feature
└── validate_order.feature # 11 features - too many!Solution: Split into sub-modules or bounded contexts
9.10 Real-World Module Structure Example
Sales Force Automation System:
features/
├── orders/
│ ├── README.md
│ ├── place_order.feature
│ ├── approve_credit_order.feature
│ └── cancel_order.feature
├── payments/
│ ├── README.md
│ ├── collect_payment.feature
│ ├── process_refund.feature
│ └── verify_mpesa_payment.feature
├── customers/
│ ├── README.md
│ ├── register_customer.feature
│ ├── update_customer_details.feature
│ └── manage_credit_limit.feature
├── inventory/
│ ├── README.md
│ ├── adjust_stock.feature
│ ├── transfer_stock.feature
│ └── perform_stocktake.feature
├── route_planning/
│ ├── README.md
│ ├── plan_daily_route.feature
│ └── optimize_route.feature
├── visits/
│ ├── README.md
│ ├── check_in_at_customer.feature
│ └── record_visit_outcome.feature
└── pricing/
├── README.md
├── manage_price_lists.feature
├── apply_special_prices.feature
└── configure_blanket_agreements.feature9.11 Running Tests by Module
Run entire module:
cucumber features/ordersRun specific feature in module:
cucumber features/orders/place_order.featureRun smoke tests across all modules:
cucumber --tags @smokeRun specific module's smoke tests:
cucumber features/orders --tags @smokeRun cross-module integration tests:
cucumber --tags "@orders and @payments"9.12 Module Ownership
Assign ownership to teams:
# CODEOWNERS
features/orders/ @sales-team
features/payments/ @finance-team
features/inventory/ @warehouse-team
features/route_planning/ @logistics-teamBenefits:
- Clear responsibility for feature quality
- Teams can evolve their modules independently
- Easier to review changes
- Natural alignment with team structure
9.13 Module Evolution
Adding new features to existing modules:
- Check if feature fits module's purpose
- Review related features for consistency
- Update module README.md
- Add cross-references where needed
Creating new modules:
Only create a new module when:
- ✅ Represents a distinct business domain
- ✅ Has 3+ related features
- ✅ Has different stakeholders than existing modules
- ✅ Can evolve independently
Don't create a new module when:
- ❌ Only 1-2 features
- ❌ Closely coupled to existing module
- ❌ Just a technical subdivision
9.14 Module Anti-Patterns
Anti-Pattern 1: Technical Modules
# ❌ Bad - organized by technical layer
features/
├── api/
├── ui/
└── database/Solution: Organize by business domain, use tags for technical concerns
Anti-Pattern 2: Over-Modularization
# ❌ Bad - too granular
features/
├── order_creation/
├── order_validation/
├── order_pricing/
└── order_submission/Solution: Combine into orders/ module
Anti-Pattern 3: God Module
# ❌ Bad - everything in one module
features/
└── application/
├── place_order.feature
├── collect_payment.feature
├── register_customer.feature
├── adjust_stock.feature
└── ... 50 more featuresSolution: Split into domain-specific modules
Anti-Pattern 4: Duplicate Features Across Modules
# ❌ Bad - same feature in multiple modules
features/
├── orders/
│ └── place_order.feature
└── sales/
└── place_order.feature # Duplicate!Solution: Feature belongs in ONE module, use tags for cross-cutting concerns
9.15 Module Documentation Template
# [Module Name]
## Purpose
[One sentence describing the module's business purpose]
## Features
- **[Feature 1]** - [Brief description]
- **[Feature 2]** - [Brief description]
- **[Feature 3]** - [Brief description]
## Key Business Rules
- [Major rule 1]
- [Major rule 2]
- [Major rule 3]
## Stakeholders
- [Primary user role]
- [Secondary user role]
## Related Modules
- **[Module]** - [How they relate]
- **[Module]** - [How they relate]
## Dependencies
- [External system or API if applicable]
## Running Tests
```bash
# All features
cucumber features/[module]
# Smoke tests
cucumber features/[module] --tags @smoke
# Critical scenarios
cucumber features/[module] --tags @criticalRecent Changes
- [Date] - [Change description]
---
## 10. Language and Vocabulary
### 8.1 Ubiquitous Language
Use **one term for one concept** consistently across all features.
Create a domain glossary and enforce it:
**Example Domain Terms:**
- **Sales representative** (not agent, user, rep, salesperson)
- **Place an order** (not submit, create, send, save)
- **Route plan** (not schedule, itinerary, route)
- **Customer** (not client, account, buyer)
- **Credit order** (not invoice, on-account order)
### 8.2 Business Language Only
**Never use:**
- Technical terminology
- Implementation details
- UI element names
- API endpoints
- Database concepts
- Service names
- Framework terms
**Always use:**
- Domain concepts
- Business processes
- User roles
- Business outcomes
- Policy terms
### 8.3 Language Test
Ask: **"Would a non-technical stakeholder understand this sentence?"**
If no → rewrite in business language.
**Technical (wrong):**
```gherkin
When the POST request to /api/orders is processed
Then the response status is 201
And the order_id is returned in the JSON payloadBusiness (right):
When the order is placed
Then the order is submitted successfully8.4 Avoiding Ambiguity
Be specific about business terms:
Vague:
Given the order is valid
When it is processed
Then it succeedsSpecific:
Given customer "Acme Store" is within their credit limit of 10000.00
When a credit order totaling 5000.00 is placed
Then the order is submitted successfully9. Common Anti-Patterns
9.1 Feature Sprawl
Problem: Creating features for every minor variation
Example:
# ❌ These should all be one feature
Feature: Add product to order
Feature: Remove product from order
Feature: Update order quantity
Feature: Change order UOMSolution: One feature with rules and scenarios
Feature: Place an order
Rule: An order consists of one or more order items
Scenario: The one where a product is added to the order
Scenario: The one where the same product is added multiple times
Scenario: The one where an order has no items9.2 Permission/Config as Features
Problem: Treating permissions or configuration as capabilities
Example:
# ❌ Not features
Feature: User can place orders
Feature: Enable discounts
Feature: Require approvalSolution: Rules within the actual feature
Feature: Place an order
Rule: Only authorized users may place orders
Rule: Discounts may only be applied when allowed by the business
Rule: Credit orders must satisfy credit and approval policies9.3 Technical Gherkin
Problem: Exposing implementation in scenarios
Example:
# ❌ Technical language
Scenario: POST /api/orders returns 201
Given the OrderService is configured
When the HTTP POST request is sent
Then the database transaction commits
And the response JSON contains order_idSolution: Business language
Scenario: The one where an order is submitted successfully
Given a sales representative has added products to an order
When the order is placed
Then the order is submitted successfully9.4 UI Testing in Disguise
Problem: Testing UI instead of business behavior
Example:
# ❌ UI-focused
Scenario: Order form validation
Given the user is on the order page
When the Submit button is clicked without entering products
Then an error message appears
And the button is disabledSolution: Business behavior
Scenario: The one where an empty order cannot be submitted
Given a sales representative is placing an order
And no products have been added
When the order is submitted
Then the order is rejected9.5 Tautological Rules
Problem: Rules that just restate the feature
Example:
# ❌ Meaningless rules
Rule: An order must be valid
Rule: The system must work correctly
Rule: All business rules must be satisfiedSolution: Specific, meaningful rules
Rule: An order consists of one or more order items
Rule: Orders may only be placed for customers in the active route plan
Rule: Credit orders must satisfy credit and approval policies9.6 Exhaustive Permutations
Problem: Creating scenarios for every possible combination
Example:
# ❌ Excessive permutations
Scenario: Cash order with 1 item
Scenario: Cash order with 2 items
Scenario: Cash order with 3 items
Scenario: Credit order with 1 item
Scenario: Credit order with 2 items
# ... and so onSolution: Meaningful examples covering distinct behaviors
Scenario: The one where a product is added to the order
Scenario: The one where the same product is added multiple times
Scenario: The one where credit is within the allowed limit9.7 Implementation Leakage
Problem: Revealing system internals in feature files
Example:
# ❌ Implementation details exposed
Rule: Orders are validated using the OrderValidator class
Scenario: The one where the order passes validation
Given an Order entity with valid properties
When the validate() method is called
Then no ValidationException is thrownSolution: Business concepts only
Rule: An order consists of one or more order items
Scenario: The one where an empty order cannot be submitted
Given a sales representative is placing an order
And no products have been added
When the order is submitted
Then the order is rejected9.8 Vague Scenarios
Problem: Using abstract terms instead of concrete examples
Example:
# ❌ Vague and abstract
Scenario: The one where pricing is applied correctly
Given a customer with special pricing
When a product is added
Then the correct price is usedSolution: Specific, concrete examples
Scenario: The one where special price applies
Given customer "Acme Store" has special price for "Coca Cola 500ml" carton at 92.00 with minimum 5 cartons
And standard price is 95.00 per carton
When "Coca Cola 500ml" with quantity 5 cartons is added
Then the selling price is 92.00 per carton10. Case Study: Cart Management
This case study demonstrates how to apply the standard when distinguishing features from behaviors.
10.1 The Question
Should we create separate features for:
- Add to cart
- Remove from cart
- Update cart item
Or one unified feature?
10.2 Apply the Feature Test
Ask: "Does this represent a business capability that delivers value on its own?"
| Candidate | Feature? | Reason |
|---|---|---|
| Add to cart | ❌ | State mutation only |
| Remove from cart | ❌ | Corrective action |
| Update cart item | ❌ | Technical phrasing |
| Manage a cart | ✅ | Business capability |
10.3 Why "Manage a Cart" Is the Feature
Users think:
- "I'm building an order"
- "I'm adjusting what I want to buy"
They don't think in API operations.
The cart is the business concept. Add/remove/update are behaviors within that capability.
10.4 Correct Cart Feature
Feature: Manage a cart
In order to prepare an order before submission
As a sales representative
I need to manage the items in my cart
Rule: Items can be added to the cart
Scenario: The one where a product is added to an empty cart
Given a sales representative with an empty cart
When "Coca Cola 500ml" with quantity 5 cartons is added to the cart
Then the cart contains "Coca Cola 500ml" with quantity 5 cartons
Scenario: The one where the same product is added twice
Given a cart contains "Coca Cola 500ml" with quantity 5 cartons
When "Coca Cola 500ml" with quantity 3 cartons is added again
Then the cart contains "Coca Cola 500ml" with quantity 8 cartons
Rule: Items can be removed from the cart
Scenario: The one where a product is removed
Given a cart contains "Coca Cola 500ml" with quantity 5 cartons
When "Coca Cola 500ml" is removed from the cart
Then the cart no longer contains "Coca Cola 500ml"
Rule: Item quantities can be adjusted
Scenario: The one where quantity is increased
Given a cart contains "Coca Cola 500ml" with quantity 5 cartons
When the quantity is changed to 10 cartons
Then the cart contains "Coca Cola 500ml" with quantity 10 cartons10.5 When Separate Features Are Valid
Create separate features only when the action is itself a distinct business capability:
| Valid Separate Feature | Why |
|---|---|
| Convert cart to order | Distinct outcome |
| Save cart as draft | Persisted business intent |
| Share cart for approval | Cross-role capability |
10.6 The Cart-to-Order Relationship
Note that "Manage a cart" and "Place an order" are separate features because:
- Managing a cart is about preparation and exploration
- Placing an order is about commitment and recording a transaction
The cart is temporary and can be abandoned. The order is permanent and has business consequences.
This distinction matters to the business, so they are separate features.
11. Complete Example
Here's a full feature file demonstrating all principles with specific, concrete scenarios:
Feature: Place an order
In order to sell products to customers
As a sales representative
I need to place an order for a customer
# Order item construction
Rule: An order consists of one or more order items
Scenario: The one where a product is added to an empty order
Given a sales representative is placing an order for customer "Acme Store"
When "Coca Cola 500ml" with quantity 10 cartons is added to the order
Then the order contains "Coca Cola 500ml" with quantity 10 cartons
Scenario: The one where the same product and batch is added twice
Given an order contains "Coca Cola 500ml" batch "B123" with quantity 5 cartons
When "Coca Cola 500ml" batch "B123" with quantity 3 cartons is added again
Then the order contains "Coca Cola 500ml" batch "B123" with quantity 8 cartons
Scenario: The one where an empty order cannot be submitted
Given a sales representative is placing an order
And no products have been added
When the order is submitted
Then the order is rejected
# Automatic pricing
Rule: Product prices are determined by price list hierarchy
Scenario: The one where customer group price list overrides user price list
Given the sales representative has price list "Standard Wholesale" with price 95.00
And customer "Acme Store" belongs to group "Premium Retailers" with price list "Premium"
And "Coca Cola 500ml" carton costs 90.00 on "Premium"
When "Coca Cola 500ml" with quantity 1 carton is added
Then the selling price is 90.00 per carton
Scenario: The one where price changes when UOM changes
Given "Coca Cola 500ml" has prices: pieces at 10.00, cartons at 95.00
And an order contains "Coca Cola 500ml" with quantity 1 carton at 95.00
When the UOM is changed to pieces with quantity 10
Then the selling price is 10.00 per piece
# Special prices and blanket agreements
Rule: Blanket agreements take highest priority in pricing
Scenario: The one where blanket agreement price is applied
Given customer "Acme Store" has blanket agreement "BA-2024-001" for "Coca Cola 500ml" carton at 88.00
And the blanket agreement has remaining balance of 100 cartons
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the selling price is 88.00 per carton
And blanket agreement "BA-2024-001" is recorded on the order item
Rule: Special prices apply when minimum quantity is met
Scenario: The one where special price applies
Given customer "Acme Store" has special price for "Coca Cola 500ml" carton at 92.00 with minimum 5 cartons
And standard price is 95.00 per carton
When "Coca Cola 500ml" with quantity 5 cartons is added
Then the selling price is 92.00 per carton
Scenario: The one where volume discount applies
Given customer "Acme Store" has volume discounts for "Coca Cola 500ml":
| Minimum Quantity | Price |
| 10 | 92.00 |
| 20 | 90.00 |
| 50 | 87.00 |
When "Coca Cola 500ml" with quantity 25 cartons is added
Then the selling price is 90.00 per carton
# Promotions
Rule: Promotions are applied automatically to qualifying orders
Scenario: The one where percentage discount promotion applies
Given a promotion offers 10% discount on "Coca Cola 500ml" with minimum 10 cartons
And standard price is 95.00 per carton
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the selling price is 85.50 per carton
And promotion type is "Percentage Discount"
Scenario: The one where free product promotion applies
Given a promotion offers 2 free pieces for every 10 cartons of "Coca Cola 500ml"
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the order contains "Coca Cola 500ml" 10 cartons at standard price
And the order contains "Coca Cola 500ml" 2 pieces at 0.00
And the free items have promotion type "Free Product"
Scenario: The one where promotions do not apply to blanket priced items
Given customer has blanket agreement for "Coca Cola 500ml" at 88.00
And a promotion offers 10% discount on "Coca Cola 500ml"
And promotion override is not allowed
When "Coca Cola 500ml" with quantity 10 cartons is added
Then the selling price is 88.00 per carton
And no promotion is applied
# Stock validation
Rule: Stock must be sufficient for sales and samples
Scenario: The one where stock is insufficient
Given "Coca Cola 500ml" batch "B123" has 5 cartons in stock
When "Coca Cola 500ml" batch "B123" with quantity 10 cartons is added to a sale
Then the item is rejected due to insufficient stock
Scenario: The one where adding to existing quantity exceeds stock
Given "Coca Cola 500ml" batch "B123" has 50 cartons in stock
And the order already contains "Coca Cola 500ml" batch "B123" with 45 cartons
When "Coca Cola 500ml" batch "B123" with quantity 10 cartons is added
Then the item is rejected due to insufficient stock
# Route plan constraints
Rule: Orders may only be placed for customers in the active route plan
Scenario: The one where customer is in route plan
Given customer "Acme Store" is in today's active route plan
When the order is placed
Then the order is submitted successfully
Scenario: The one where customer is not in route plan
Given customer "Acme Store" is not in today's active route plan
When the order is placed
Then the order is rejected
# Permissions
Rule: Only authorized users may place orders
Scenario: The one where user has permission
Given the sales representative has "place orders" permission
When the order is placed
Then the order is submitted successfully
Scenario: The one where user lacks permission
Given the sales representative does not have "place orders" permission
When the order is placed
Then the order is rejected
# Credit and approvals
Rule: Credit limits must be respected
Scenario: The one where credit is within limit
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 3000.00
When a credit order totaling 5000.00 is placed
Then the order is submitted successfully
Scenario: The one where credit exceeds limit
Given customer "Acme Store" has credit limit of 10000.00
And current balance is 8000.00
When a credit order totaling 5000.00 is placed
Then the order is rejected
And the error message indicates credit limit exceeded
Scenario: The one where discount approval is required
Given discount approval is required
And customer discounts totaling 500.00 have been applied
When the order is submitted
Then the order status is "Pending"
And discount status is "Pending"12. Quality Checklist
Use this checklist before merging any feature file.
Feature-Level Checks
- Represents a real, distinct business capability
- Can be explained without referencing another feature
- Uses business language exclusively
- Intent block is clear and unconditional
- Would be meaningful if removed
- Name uses active verb (e.g., "Place an order" not "Order placement")
Rule-Level Checks
- All constraints are expressed as Rules
- Rules describe what, not how
- Rules are evaluated at the same decision point as the action
- No duplication of rules across features
- No tautological or meaningless rules
- Each rule adds distinct business meaning
- Rules use declarative language
Scenario-Level Checks
- One behavior per scenario
- Friends episode notation used consistently
- Given establishes context with specific values
- When describes exactly one action with concrete details
- Then describes observable outcome with measurable results
- No technical or UI language
- Scenarios are independent
- Can be understood by non-technical stakeholders
- Scenario name clearly indicates what happens
- No vague terms - uses actual product names, quantities, prices
- No abstract descriptions - uses concrete business examples
Specificity Checks
- Product names are real (not "a product" or "product X")
- Quantities are specified (not "some quantity" or "multiple items")
- Prices are exact (not "the correct price" or "appropriate amount")
- Customer names are concrete (not "a customer" or "the user")
- Error messages are quoted exactly
- Batch numbers, order IDs, and references are specific
- Dates and times are concrete when relevant
Coverage Checks
- Positive cases documented
- Negative cases documented
- Configuration variants shown as scenarios
- Permissions modeled as rules
- Approvals modeled as rules
- Ubiquitous language used consistently
- Edge cases covered without exhaustive permutations
Documentation Quality
- Non-technical stakeholders can read and understand
- Developers can implement from the specification
- Testers can verify behavior
- Product owners can validate requirements
- No ambiguity in expected behavior
- Comments (if any) only clarify organization, not behavior
13. Getting Started
13.1 For New Projects
- Identify your core business capabilities — what can users actually do?
- Create one feature file per capability — start with the most important
- Document the happy path first — get agreement on success
- Add constraints as rules — identify what can go wrong
- Demonstrate with specific scenarios — provide concrete examples with real values
- Review with stakeholders — ensure everyone understands
- Refine vocabulary — establish ubiquitous language
13.2 For Existing Projects
- Audit existing documentation — identify features vs rules vs technical tests
- Consolidate related features — reduce sprawl
- Extract rules from conditional logic — make policies explicit
- Rewrite in business language — remove technical terminology
- Make scenarios concrete — replace vague terms with specific examples
- Align with domain experts — validate understanding
- Establish standards — use this guide
- Migrate gradually — improve one feature at a time
13.3 Building Team Alignment
- Run workshops with mixed teams (business + technical)
- Review features together before implementation
- Use features in planning — estimate from scenarios
- Reference scenarios in code — maintain traceability
- Update features when requirements change — keep documentation living
- Celebrate good examples — recognize quality documentation
- Practice specificity — challenge vague scenarios in reviews
14. Summary
Living documentation with BDD features succeeds when you:
- Model capabilities, not implementations
- Use business language exclusively
- Organize with Features → Rules → Scenarios
- Demonstrate rules with concrete, specific examples
- Use real values, not abstract placeholders
- Maintain consistency across all features
- Keep documentation close to reality
This isn't just about writing better tests—it's about creating a shared understanding that bridges business and technology, remains accurate over time, and serves as the definitive source of truth for what your system does.
Key Principles to Remember:
Features = capabilities
Rules = constraints
Scenarios = concrete examples with specific values
Consistency matters more than perfection.
When in doubt, ask:
- Is this a capability or a constraint?
- Would a non-technical person understand this?
- Does this describe what the business needs or how we build it?
- Am I being specific enough? (Real names, actual quantities, exact prices)
- Could someone implement/test this from my description alone?
Follow these principles, and your feature files will serve as true living documentation that everyone can understand, trust, and use.