Serial scenarios¶
Some scenarios cannot run in parallel because they depend on shared state,
exclusive resources, or have side effects that would conflict with other tests.
behave-pool provides the @serial tag to handle these cases.
How it works¶
When behave-pool encounters a feature file containing @serial-tagged
scenarios, it:
- Parallel phase — Runs all non-serial features across N worker processes.
- Serial phase — After all parallel workers complete, runs
@serialfeatures one at a time in a single worker process.
This ensures serial scenarios never run concurrently with each other or with parallel work.
Tagging scenarios¶
Single scenario as serial¶
Feature: Database operations
Scenario: Query user data
Given a user exists
When I query the database
Then I should see the user record
@serial
Scenario: Run database migration
Given the database is empty
When I run the migration script
Then all tables should exist
In this example:
- "Query user data" runs in the parallel phase.
- "Run database migration" runs in the serial phase, after all parallel work is done.
Entire feature as serial¶
@serial
Feature: Cleanup operations
Scenario: Remove temporary files
Given temp files exist
When I run cleanup
Then no temp files should remain
Scenario: Reset test database
Given a test database exists
When I reset it
Then the database should be empty
When a feature is tagged @serial, all scenarios in that feature run in
the serial phase.
Multiple serial scenarios¶
Feature: Order processing
Scenario: Create order
Given a customer
When I create an order
Then the order should be saved
@serial
Scenario: Process payment
Given an order exists
When I process the payment
Then the payment should be confirmed
@serial
Scenario: Send confirmation email
Given a confirmed order
When I send the confirmation email
Then the email should be sent
Serial scenarios run one at a time in the order they appear in the feature file. "Process payment" runs first, then "Send confirmation email".
Execution order¶
┌──────────────────────────────────────────────────────┐
│ ParallelRunner │
│ │
│ Phase 1: PARALLEL │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Worker 0 │ │ Worker 1 │ │ Worker 2 │ │ Worker 3 │ │
│ │ feature A│ │ feature B│ │ feature C│ │ feature D│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Phase 2: SERIAL (after all workers finish) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Serial 1 │ → │ Serial 2 │ → │ Serial 3 │ │
│ │ (worker) │ │ (worker) │ │ (worker) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────────────────────────────────────────┘
Serial phase only starts after parallel phase
If any parallel worker fails, the serial phase still runs. This ensures
cleanup scenarios (e.g., @serial teardown) always execute. However,
if the stop_event is set (e.g., due to a worker crash), the serial
phase is skipped.
Combining with other tags¶
@serial can be combined with any other tags:
@serial @slow @database
Scenario: Full database rebuild
Given a populated database
When I rebuild all indexes
Then all indexes should be valid
You can use Behave's --tags filtering alongside @serial:
# Run only serial scenarios
behave --runner=parallel --parallel 4 --tags=@serial features/
# Exclude serial scenarios from parallel run
behave --runner=parallel --parallel 4 --tags=~@serial features/
Common use cases¶
Database migrations¶
@serial
Scenario: Run schema migration
Given the database is at version 1
When I run the migration to version 2
Then the schema should be at version 2
Shared file system operations¶
@serial
Scenario: Write to shared log file
Given a shared log file exists
When I append an entry
Then the log file should contain the entry
External API rate-limited calls¶
@serial
Scenario: Call rate-limited API
Given the API allows 1 request per second
When I make a request
Then I should receive a valid response
Best practices¶
- Tag at the scenario level when only specific scenarios need serialization.
- Tag at the feature level when all scenarios in a feature are non-parallelizable.
- Keep serial scenarios fast — they run sequentially and can become a bottleneck if there are many slow serial scenarios.
- Use
@serialfor correctness, not convenience — only tag scenarios that truly cannot run in parallel.