Skip to content

What is Pest BDD?

Pest BDD is a plugin for Pest PHP that brings Behavior-Driven Development (BDD) capabilities to your test suite. It allows you to write human-readable feature specifications in Gherkin syntax and bind them to PHP code using native PHP 8 attributes.

The BDD Philosophy

Behavior-Driven Development is a software development approach that emphasizes collaboration between developers, QA, and non-technical stakeholders. At its core, BDD uses a ubiquitous language that everyone can understand.

The Three Amigos

BDD encourages collaboration through:

  • Business - Defines what the system should do
  • Development - Implements the behavior
  • Testing - Verifies the behavior works correctly

Feature files written in Gherkin serve as a common language that bridges these perspectives.

Key Concepts

Features

A feature represents a piece of functionality from the user's perspective:

gherkin
Feature: User Registration
  As a visitor
  I want to create an account
  So that I can access member features

Scenarios

Scenarios are concrete examples of how a feature should behave:

gherkin
Scenario: Successful registration
  Given I am on the registration page
  When I fill in valid details
  Then I should see a welcome message

Steps

Steps are the building blocks of scenarios. They follow the Given-When-Then pattern:

  • Given - Sets up the initial context (Arrange)
  • When - Describes the action taken (Act)
  • Then - Verifies the expected outcome (Assert)

How Pest BDD Works

Pest BDD takes a unique approach compared to traditional BDD frameworks:

1. PHP 8 Attributes

Instead of annotations or configuration files, step definitions use native PHP 8 attributes:

php
#[Given('a user {name} exists')]
public function userExists(string $name): User
{
    return User::factory()->create(['name' => $name]);
}

2. Type-Based Parameter Matching

The type hint in your method signature determines how parameters are extracted from step text:

php
// Pattern: "user has {count} items"
// Text: "user has 5 items"
// Extracted: $count = 5 (as integer)

#[Given('user has {count} items')]
public function userHasItems(int $count): void
{
    // $count is automatically cast to int
}

3. Auto-Discovery

Pest BDD automatically discovers:

  • Step definitions - Classes with #[Given], #[When], #[Then] attributes
  • Feature files - .feature files in tests/Behaviors/

No configuration files needed.

4. Context Injection

Return values from steps are stored in a scenario context and automatically injected into subsequent steps:

php
#[Given('a user {name} exists')]
public function userExists(string $name): User
{
    return User::factory()->create(['name' => $name]);
}

#[Then('the user should be active')]
public function userShouldBeActive(User $user): void
{
    // $user is automatically injected from context
    expect($user->is_active)->toBeTrue();
}

When to Use BDD

BDD is particularly valuable when:

  • Collaboration is key - Multiple stakeholders need to understand system behavior
  • Complex business logic - Rules that benefit from concrete examples
  • Living documentation - Tests that serve as up-to-date specifications
  • Acceptance testing - Verifying features work from end to end

BDD vs Unit Testing

BDD and unit testing serve different purposes and complement each other:

AspectBDD (Pest BDD)Unit Testing (Pest)
ScopeFeature/behavior levelFunction/method level
AudienceAll stakeholdersDevelopers
LanguageNatural language (Gherkin)Code
PurposeAcceptance criteriaImplementation correctness
SpeedSlower (integration)Faster (isolated)

The TDD Double Loop pattern shows how to effectively combine both approaches.

Released under the MIT License.