Writing Features
Feature files are the heart of BDD. Written in Gherkin syntax, they describe system behavior in a human-readable format that serves as both documentation and executable tests.
Gherkin Basics
Gherkin is a domain-specific language designed to be understandable by everyone on the team—developers, testers, and business stakeholders alike.
Feature
Every feature file starts with the Feature keyword, followed by a name and optional description:
Feature: Shopping Cart
As a customer
I want to add items to my cart
So that I can purchase them laterThe description (everything after the feature name) is free-form text. A common format is the "As a... I want... So that..." template, but any description works.
Scenarios
Scenarios are concrete examples of how the feature should behave:
Feature: Shopping Cart
Scenario: Add item to empty cart
Given I have an empty cart
When I add "Widget" to the cart
Then I should see 1 item in my cart
Scenario: Add multiple items
Given I have an empty cart
When I add "Widget" to the cart
And I add "Gadget" to the cart
Then I should see 2 items in my cartEach scenario is independent and should not depend on other scenarios.
Steps
Steps are the building blocks of scenarios. They follow a specific structure:
| Keyword | Purpose | Testing Phase |
|---|---|---|
| Given | Set up initial state | Arrange |
| When | Perform an action | Act |
| Then | Verify the outcome | Assert |
| And | Continue previous step type | - |
| But | Continue with negation | - |
Scenario: User login
Given a user "john@example.com" exists # Arrange
And the user has password "secret" # Arrange (continued)
When I submit login with "john@example.com" # Act
And I enter password "secret" # Act (continued)
Then I should be logged in # Assert
But I should not see the login form # Assert (continued)Step Text Patterns
Plain Text Steps
Simple steps with no parameters:
Given I am on the home page
When I click the login button
Then I should see the dashboardSteps with Parameters
Parameters are enclosed in quotes for strings or written as bare numbers for integers:
Given a user "John" exists # String parameter
When I add 5 items to the cart # Integer parameter
Then the total should be 99.99 # Float parameterMulti-line Parameters
For longer text, use doc strings (triple quotes):
Scenario: Post a comment
Given I am logged in
When I post a comment:
"""
This is a multi-line comment.
It can span several lines.
Useful for longer text content.
"""
Then I should see my commentTables
Use tables for structured data:
Scenario: Bulk user creation
Given the following users exist:
| name | email | role |
| John | john@test.com | admin |
| Jane | jane@test.com | user |
| Bob | bob@test.com | user |
Then I should see 3 users in the systemFile Organization
Directory Structure
Place feature files in tests/Behaviors/:
tests/
├── Behaviors/
│ ├── authentication/
│ │ ├── login.feature
│ │ ├── logout.feature
│ │ └── password-reset.feature
│ ├── cart/
│ │ ├── add-items.feature
│ │ └── checkout.feature
│ └── user-management.feature
└── Steps/
└── ...Pest BDD automatically discovers all .feature files in this directory tree.
Naming Conventions
Feature files should:
- Use lowercase with hyphens:
user-registration.feature - Be descriptive:
shopping-cart-checkout.feature - Group related scenarios in one file
One Feature Per File
Each file should contain exactly one feature:
# Good: tests/Behaviors/user-registration.feature
Feature: User Registration
...
# Avoid: multiple features in one fileComments
Add comments with the # character:
Feature: User Authentication
# This feature covers all authentication flows
# Basic login scenario
Scenario: Successful login
Given a user exists
# TODO: Add two-factor authentication step
When I login with valid credentials
Then I should be logged inTags
Tags categorize scenarios for filtering and organization:
@authentication @smoke
Feature: Login
@critical @fast
Scenario: Valid credentials
Given a user exists
When I login with valid credentials
Then I should be logged in
@slow @integration
Scenario: Remember me functionality
Given a user exists
When I login with "remember me" checked
Then I should stay logged in for 30 daysTags can be applied to:
- Features (applies to all scenarios in the feature)
- Scenarios (applies only to that scenario)
Learn more in Tag Filtering.
Best Practices
Write Declarative Steps
Good - Describes intent:
Given a logged-in admin user
When I create a new product
Then the product should be visibleAvoid - Too implementation-specific:
Given I open browser to "/login"
And I type "admin" in field "username"
And I type "password" in field "password"
And I click button "submit"Keep Scenarios Focused
Each scenario should test one specific behavior:
Good:
Scenario: Add item to cart
Given I have an empty cart
When I add "Widget" to the cart
Then I should see 1 item in my cartAvoid:
Scenario: Complete shopping experience
Given I am a registered user
When I login
And I browse products
And I add item to cart
And I checkout
And I pay
Then I should receive confirmationUse Consistent Language
Create a ubiquitous language for your domain:
# Consistent terminology
Given a customer "John" exists
When the customer adds "Widget" to cart
Then the customer's cart should contain "Widget"
# Avoid mixing terms
Given a user "John" exists # user?
When the client adds "Widget" # client?
Then the buyer's cart should... # buyer?Scenario Independence
Each scenario should be independent and not rely on others:
# Good: Each scenario sets up its own state
Scenario: Add to empty cart
Given I have an empty cart
When I add "Widget"
Then cart should have 1 item
Scenario: Add to existing cart
Given I have a cart with "Gadget"
When I add "Widget"
Then cart should have 2 itemsExample: Complete Feature File
Here's a well-structured feature file:
@cart @e-commerce
Feature: Shopping Cart
As a customer
I want to manage items in my shopping cart
So that I can purchase products I'm interested in
Background:
Given I am a logged-in customer
@smoke @critical
Scenario: Add item to empty cart
Given I have an empty cart
When I add "Wireless Mouse" to the cart
Then I should see 1 item in my cart
And the cart total should be $29.99
@smoke
Scenario: Add multiple items
Given I have an empty cart
When I add "Wireless Mouse" to the cart
And I add "USB Cable" to the cart
Then I should see 2 items in my cart
Scenario: Remove item from cart
Given I have a cart with "Wireless Mouse"
When I remove "Wireless Mouse" from the cart
Then I should have an empty cart
Scenario: Update item quantity
Given I have a cart with "Wireless Mouse"
When I update the quantity of "Wireless Mouse" to 3
Then I should see 3 "Wireless Mouse" in my cart
And the cart total should be $89.97
@slow
Scenario: Cart persists across sessions
Given I have a cart with "Wireless Mouse"
When I logout and login again
Then I should still see "Wireless Mouse" in my cart