bdd_flutter 0.2.0
bdd_flutter: ^0.2.0 copied to clipboard
A powerful Flutter package that simplifies Behavior Driven Development (BDD) by automatically generating test files from Gherkin feature files
๐ BDD Flutter #
A powerful 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
.feature
files written in Gherkin syntax - โก Generate boilerplate test files automatically
- ๐งช Support for both widget tests and unit tests
- โ๏ธ Configurable test generation
๐ฆ Installation #
Add the following dependencies to your package's pubspec.yaml
file:
dev_dependencies:
bdd_flutter: any
build_runner: any
๐ Quick Start #
- Create a
.feature
file in your project:
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:
flutter pub run build_runner build
- Run your tests:
flutter test
๐ก Recommendations #
When working with generated test files, follow these best practices:
-
Generated Files:
- Generated files will have the
.g.dart
extension (e.g.,counter_test.bdd_test.g.dart
orcounter_scenarios.g.dart
) - After implementing your tests, it's recommended to:
- Remove the
.g
extension from the file name - Add an ignore decorator to your feature file (@ignore)
- Remove the
- This will prevent the generated files from being overwritten by subsequent builds
- Generated files will have the
-
Feature File Ignore: Add this comment at the top of your feature file:
@ignore Feature: Counter
This approach ensures that:
- Your implemented tests won't be overwritten by subsequent builds
- Generated files are properly ignored in version control
- You maintain a clean project structure
โ๏ธ Configuration #
Configure test generation in your build.yaml
:
targets:
$default:
builders:
bdd_flutter|bdd_test_builder:
options:
generate_widget_tests: false # Default: true
enable_reporter: true # Default: false
ignore_features:
- "test/features/ignored.feature"
- "test/features/another_ignored.feature"
Configuration Options #
Option | Type | Default | Description |
---|---|---|---|
generate_widget_tests |
bool | true | Generate widget tests when true, unit tests when false |
enable_reporter |
bool | false | Enable/disable test reporter |
ignore_features |
List | [] | List of feature file paths to ignore during generation |
๐ท๏ธ Decorators #
Control test generation with decorators:
Decorator | Scope | Description |
---|---|---|
@unitTest |
Feature, Scenario | Generate unit test (overrides config) |
@widgetTest |
Feature, Scenario | Generate widget test (overrides config) |
@className("CustomName") |
Scenario | Generate custom class name |
@enableReporter |
Feature | Enable test reporter |
@disableReporter |
Feature | Disable test reporter |
๐ก Decorators follow a hierarchy: Scenario-level decorators override Feature-level ones.
๐ Complete Example #
1. Feature File (counter.feature
) #
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 |
2. Generated Files #
counter_scenarios.dart
import 'package:flutter_test/flutter_test.dart';
class IncrementScenario {
static Future<void> iHaveACounterWithValue0(WidgetTester tester) async {
// TODO: Implement Given I have a counter with value 0
}
static Future<void> iIncrementTheCounterBy(WidgetTester tester, dynamic value) async {
// TODO: Implement When I increment the counter by <value>
}
static Future<void> theCounterShouldHaveValue(WidgetTester tester, dynamic expected_value) async {
// TODO: Implement Then the counter should have value <expected_value>
}
}
counter_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'counter_scenarios.dart';
void main() {
group('Counter', () {
testWidgets('Increment', (tester) async {
await IncrementScenario.iHaveACounterWithValue0(tester);
// Example with values: 1, 1
await IncrementScenario.iIncrementTheCounterBy(tester, '1');
await IncrementScenario.theCounterShouldHaveValue(tester, '1');
// Example with values: 2, 2
await IncrementScenario.iIncrementTheCounterBy(tester, '2');
await IncrementScenario.theCounterShouldHaveValue(tester, '2');
// Example with values: 3, 3
await IncrementScenario.iIncrementTheCounterBy(tester, '3');
await IncrementScenario.theCounterShouldHaveValue(tester, '3');
});
});
}
๐ค Contributing #
We welcome contributions! Please feel free to:
- Open an issue
- Submit a pull request
- Share your feedback
๐ License #
This project is licensed under the MIT License - see the LICENSE file for details.