BDD Flutter
A Flutter package that simplifies Behavior Driven Development (BDD) by automatically generating test files from Gherkin feature files. Write expressive tests in plain English using Given/When/Then scenarios and let BDD Flutter handle the boilerplate code generation.
Features
- Parse
.featurefiles written in Gherkin syntax (Given/When/Then/And) - Generate boilerplate test files automatically
- Support for both widget tests and unit tests
- Incremental generation — new scenarios are appended without overwriting existing implementations
- Instance-based scenario classes for shared state between steps
- Background support for shared setup steps
- Examples tables for parameterized scenarios
- Configurable via
.bdd_flutter/config.yaml - Manifest tracking in
.bdd_flutter/manifest.yaml
Installation
Add to your pubspec.yaml:
dev_dependencies:
bdd_flutter: latest
Quick Start
- Create a
.featurefile in your test folder:
Feature: Counter
Scenario: Increment
Given I have a counter with value 0
When I increment the counter by <value>
Then the counter should have value <expected_value>
Examples:
| value | expected_value |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
- Generate test files:
dart run bdd_flutter build
-
Implement the generated step methods in
counter.bdd_scenarios.dart -
Run your tests with BDD report:
dart run bdd_flutter test
Or run normally with flutter test.
Generated Files
The generator creates two files per .feature file:
.bdd_scenarios.dart— Scenario classes with step method stubs (your implementation goes here).bdd_test.dart— Test orchestration file (auto-generated, do not edit)
How It Works
- Scenario classes use instance methods, so you can add
latefields for shared state (mocks, widgets, etc.) - Each test instantiates a fresh scenario for proper test isolation
- When you add a new scenario to a
.featurefile, only the new scenario class is appended — existing implementations are preserved - The test file is always regenerated (it contains no user code)
Example Output
counter.bdd_scenarios.dart
import 'package:flutter_test/flutter_test.dart';
class IncrementScenario {
Future<void> iHaveACounterWithValue0(WidgetTester tester) async {
// TODO: Implement Given I have a counter with value 0
}
Future<void> iIncrementTheCounterByValue(WidgetTester tester, String value) async {
// TODO: Implement When I increment the counter by <value>
}
Future<void> theCounterShouldHaveValueExpectedValue(WidgetTester tester, String expectedValue) async {
// TODO: Implement Then the counter should have value <expected_value>
}
}
counter.bdd_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'counter.bdd_scenarios.dart';
void main() {
group('Counter', () {
testWidgets('Increment', (tester) async {
final scenario = IncrementScenario();
final examples = [
{'value': '1', 'expectedValue': '1'},
{'value': '2', 'expectedValue': '2'},
{'value': '3', 'expectedValue': '3'},
];
for (var example in examples) {
await scenario.iIncrementTheCounterByValue(tester, example['value']!);
await scenario.theCounterShouldHaveValueExpectedValue(tester, example['expectedValue']!);
}
});
});
}
Configuration
Configure the generator in .bdd_flutter/config.yaml:
# Where to scan for .feature files
test_dir: "test/"
# Generate widget tests or unit tests
generate_widget_tests: true
# Feature files to skip during generation
ignore_features:
- test/features/login.feature
- test/features/registration.feature
# Imports added to every generated .bdd_scenarios.dart file
additional_imports:
- "package:mocktail/mocktail.dart"
- "test/helpers/test_helpers.dart"
# Suffix for generated scenario class names (default: "Scenario")
# e.g., "Steps" → IncrementSteps instead of IncrementScenario
scenario_suffix: "Scenario"
Or use --force to regenerate everything:
dart run bdd_flutter build --force
Config Options
| Option | Type | Default | Description |
|---|---|---|---|
test_dir |
String | test/ |
Directory to scan for .feature files |
generate_widget_tests |
bool | true | Generate widget tests when true, unit tests when false |
ignore_features |
List | [] | Feature file paths to skip during generation |
additional_imports |
List | [] | Imports added to every generated scenario file |
scenario_suffix |
String | Scenario |
Class name suffix (e.g., Steps for IncrementSteps) |
CLI Flags
Commands
| Command | Description |
|---|---|
build |
Generate test files from .feature files |
build --force |
Force regenerate all files (overwrites existing) |
test |
Run all tests with formatted BDD and non-BDD reports |
Test Report
Running dart run bdd_flutter test discovers all test files in your project and produces a formatted report with two sections:
- BDD Test Report —
.bdd_test.dartfiles grouped by Feature with Scenario pass/fail - Non-BDD Test Report — regular
_test.dartfiles grouped by file name and test group
Example Output
Running 8 BDD + 1 regular test file(s)...
BDD Test Report
==================================================
Feature: Calculator
✓ Add two numbers (170ms)
✓ Subtract two numbers (7ms)
✓ Multiply two numbers (4ms)
✓ Divide two numbers (4ms)
Feature: Counter
✓ Increment (152ms)
✓ Decrement (6ms)
Feature: Login
✓ Successful login (150ms)
✓ Failed login shows error (8ms)
✓ Logout after login (4ms)
Non-BDD Test Report
==================================================
Test File: string_utils_test.dart
capitalize
✓ capitalizes first letter (19ms)
✓ returns empty string for empty input (2ms)
✓ handles single character (1ms)
add
✓ adds two positive numbers (2ms)
✓ adds negative numbers (3ms)
✓ adds zero (2ms)
──────────────────────────────────────────────────
15 tests: 15 passed, 0 failed
Time: 2781ms
Decorators
Control test type with standard Gherkin tags:
| Decorator | Scope | Description |
|---|---|---|
@unitTest |
Feature, Scenario | Generate unit test (overrides config) |
@widgetTest |
Feature, Scenario | Generate widget test (overrides config) |
Scenario-level decorators override Feature-level ones.
To skip generation for specific features, use ignore_features in config.
Generation Modes
Incremental (Default)
dart run bdd_flutter build
- Skips unchanged features (tracked via manifest)
- New scenarios are appended to existing scenario files — implementations are preserved
- Test files are regenerated to include all scenarios
Force Regenerate
dart run bdd_flutter build --force
- Regenerates all files from scratch
- Overwrites existing scenario implementations — use with caution
Project Structure
your_project/
├── .bdd_flutter/
│ ├── config.yaml # Configuration (commit to version control)
│ └── manifest.yaml # Generation tracking (commit to version control)
├── test/
│ └── login/
│ ├── login.feature
│ ├── login.bdd_scenarios.dart # Your implementations
│ └── login.bdd_test.dart # Auto-generated orchestration
└── pubspec.yaml
Best Practices
-
Version Control — Keep both
config.yamlandmanifest.yamlin version control. The manifest prevents incremental builds from overwriting implemented code on fresh clones. -
Scenario Files — Implement your test logic in
.bdd_scenarios.dart. Uselatefields for shared state between steps (mocks, providers, widgets). -
Test Files — Do not edit
.bdd_test.dartfiles. They are regenerated automatically and contain no user code. -
Adding Scenarios — When you add new scenarios to a
.featurefile, runbuild— new scenario classes are appended without touching existing ones. -
Feature Files — Keep feature files clean. Only use
@unitTest/@widgetTestdecorators. All other configuration belongs in.bdd_flutter/config.yaml.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Libraries
- bdd_flutter
- A Flutter package for Behavior-Driven Development (BDD) testing.