Advanced
Chapter 20 · 12 min read
Best Practices & Anti-Patterns
Write maintainable BDD suites — avoid common anti-patterns, follow Gherkin writing guidelines, and structure scalable Cucumber projects.
BDD Best Practices & Anti-Patterns
The difference between a BDD suite that scales and one that becomes a maintenance nightmare comes down to how you write scenarios, structure step definitions, and organize your project.
Golden Rules
- Write declarative, not imperative — describe what, not how
- One scenario = one behavior — don't test everything in one scenario
- Thin steps, fat page objects — keep step definitions as thin orchestrators
- Use Background wisely — only for truly common preconditions
- Tags over folders — organize by tags, not deep folder hierarchies
Common Anti-Patterns
- UI-coupled steps —
When I click the #submit-btn(too technical) - Scenario novels — 20+ steps in one scenario (too long)
- Incidental details — specifying data that doesn't affect the outcome
- Coupled scenarios — Scenario B depends on Scenario A running first
good_vs_bad.feature
# ===== BAD: Imperative (how) =====
# Scenario: Login
# Given I open Chrome browser
# And I navigate to "https://app.com/login"
# And I find element by id "username"
# And I type "admin" into it
# And I find element by id "password"
# And I type "secret" into it
# And I click the element with css ".btn-submit"
# And I wait 3 seconds
# Then the URL should be "https://app.com/dashboard"
# ===== GOOD: Declarative (what) =====
Feature: User Authentication
Scenario: Admin can access the dashboard
Given the user is on the login page
When the user logs in as "admin"
Then the dashboard should be displayed
# GOOD: Scenario Outline for data variations
Scenario Outline: Role-based access
Given the user logs in as "<role>"
Then they should see the "<section>" section
Examples:
| role | section |
| admin | User Mgmt |
| manager | Team Reports |
| viewer | Read-Only |
# GOOD: Independent scenarios (no coupling)
Scenario: New user sees onboarding
Given a newly registered user
When they log in for the first time
Then the onboarding wizard should appear
# GOOD: Business-readable, no technical details
Scenario: Expired session requires re-login
Given the user is logged in
And the session has expired
When the user tries to access the dashboard
Then they should be redirected to the login page
architecture-tips.txt
# Project Architecture Best Practices
1. STEP DEFINITIONS: Keep thin, delegate to helpers
LoginSteps -> LoginPage -> WebDriver
NOT: LoginSteps -> WebDriver directly
2. FEATURE FILES: One feature per business capability
login.feature, checkout.feature, search.feature
NOT: test1.feature, test2.feature
3. TAGS: Use consistently
@smoke — critical happy paths (run on every commit)
@regression — full suite (run nightly)
@wip — work in progress (always excluded)
@api — no browser needed
@ui — browser required
4. SCENARIOS: 3-7 steps each
Too short = not testing enough
Too long = testing too much at once
5. STEP REUSE: >80% of steps should be reusable
Generic: "the user clicks the {string} button"
NOT: "the user clicks the login page submit button"
6. DATA: Use Scenario Outline for data variations
NOT: copy-paste scenarios with different values
7. INDEPENDENCE: Each scenario runs in isolation
Setup via Background or hooks, not by running other scenarios
good_vs_bad.feature
# ===== BAD: Imperative (how) =====
# Scenario: Login
# Given I open Chrome browser
# And I navigate to "https://app.com/login"
# And I find element by id "username"
# And I type "admin" into it
# Then the URL should be "https://app.com/dashboard"
# ===== GOOD: Declarative (what) =====
Feature: User Authentication
Scenario: Admin can access the dashboard
Given the user is on the login page
When the user logs in as "admin"
Then the dashboard should be displayed
Scenario Outline: Role-based access
Given the user logs in as "<role>"
Then they should see the "<section>" section
Examples:
| role | section |
| admin | User Mgmt |
| manager | Team Reports |
| viewer | Read-Only |
Scenario: New user sees onboarding
Given a newly registered user
When they log in for the first time
Then the onboarding wizard should appear
Scenario: Expired session requires re-login
Given the user is logged in
And the session has expired
When the user tries to access the dashboard
Then they should be redirected to the login page
behave-tips.txt
# Behave-Specific Best Practices
1. CONTEXT OBJECT: Use wisely
context.driver = webdriver # OK — shared state
context.test_data = {} # OK — scenario data
context.some_flag = True # Avoid — use tags instead
2. ENVIRONMENT.PY: Single source for hooks
before_scenario: setup driver
after_scenario: screenshot + quit
before_tag: conditional setup
3. STEP FILE ORGANIZATION:
common_steps.py — generic, reusable steps
login_steps.py — feature-specific steps
api_steps.py — API testing steps
NOT: steps.py — one giant file
4. TAGS: Filter effectively
behave --tags="@smoke and not @wip"
behave --tags="@api" (no browser needed)
5. REPORTING: Always generate reports
behave -f allure_behave.formatter:AllureFormatter -o reports/
behave --junit --junit-directory=reports/junit/
6. HEADLESS IN CI:
if os.getenv('HEADLESS'):
options.add_argument('--headless=new')
Cucumber BDD
Advanced
Best Practices & Anti-Patterns
Written by PV
© 2026 All Rights Reserved