Skip to content

Commit d71c807

Browse files
authored
Update bdd flutter blog (#147)
* Updated link of Introducing BDD * exitAfterTestRun is removed from gherkin 2.0.0 * Fixed type incompatible * Addressed reviews * Fixed grammatical errors as suggested * Added blog updated date * Fixed grammatical errors as suggested
1 parent f2f2598 commit d71c807

File tree

1 file changed

+28
-29
lines changed

1 file changed

+28
-29
lines changed

src/assets/BDDWithFlutter/BDDWithFlutter.md

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,35 @@ authorName: Artur Neumann
44
authorAvatar: https://www.jankaritech.com/images/2019/06/11/p1070364-c-light-800.jpg
55
authorLink: https://github.com/individual-it
66
createdAt: June 3, 2020
7+
updatedAt: July 8, 2024
78
tags: bdd, testing, flutter, dart
89
banner: https://raw.githubusercontent.com/JankariTech/blog/master/src/imgs/fallback_banner.png
910
seriesTitle: Behaviour Driven Development
1011
episode: 2
1112
---
1213

13-
This tutorial will first show how to test a flutter app using the Gherkin language and in the second part walk through an example of BDD (Behavior Driven Development) in the same App.
14+
This tutorial will first show how to test a Flutter app using the [Gherkin](https://cucumber.io/docs/gherkin/reference/) language and in the second part walk through an example of BDD (Behavior Driven Development) in the same app.
1415

15-
Flutter uses different types of tests [(unit, widget, integration)](https://flutter.dev/docs/testing). You should have all types of tests in your app, most of your tests should be unit tests, less widget and a few integration tests. The [test pyramid](https://martinfowler.com/bliki/TestPyramid.html) explains the principle well (using different words for the test-types).
16+
Flutter uses different types of tests [(unit, widget, integration)](https://flutter.dev/docs/testing/overview). You should have all types of tests in your app. Most of your tests should be unit tests, less widget tests and a few integration tests. The [test pyramid](https://martinfowler.com/bliki/TestPyramid.html) explains the principle well (though using different names for the test types).
1617

17-
In this tutorial, I want to help you to start with integration tests but go a step further than the description in the [flutter documentation](https://flutter.dev/docs/testing#integration-tests) and use the Gherkin language to describe the expected behavior.
18-
The basic idea behind Gherkin/Cucumber is to have a semi-structured language to be able to define the expected behaviour and requirements in a way that all stakeholders of the project (customer, management, developer, QA, etc.) understand them. Using Gherkin helps to reduce misunderstandings, wasted resources and conflicts by improving communication. Additionally, you get a documentation of your project, and finally you can use the Gherkin files to run automated tests.
18+
In this tutorial, I want to help you to start with integration tests. However, we will go a step further than the description in the [Flutter documentation](https://flutter.dev/docs/testing#integration-tests) and use the Gherkin language to describe the expected behavior.
19+
The basic idea behind Gherkin is to have a semi-structured language to be able to define the expected behaviour and requirements in a way that all stakeholders of the project (customer, management, developer, QA, etc.) understand them. Using Gherkin helps to reduce misunderstandings, wasted resources and conflicts by improving communication. Additionally, you get a documentation of your project, and finally you can use the Gherkin files to run automated tests.
1920

20-
If you write the Gherkin files, before you write the code, you have reached the final level, as this is called BDD (Behavior Driven Development)!
21+
If you write the Gherkin files before you write the code, you have reached the final level. This is called BDD!
2122

2223
Here are some readings about BDD and Gherkin:
23-
- ["Introducing BDD", by Dan North (2006)](http://blog.dannorth.net/introducing-bdd)
24-
- [Wikipedia](https://en.wikipedia.org/wiki/Behavior-driven_development)
25-
- ["The beginner's guide to BDD (behaviour-driven development)", By Konstantin Kudryashov, Alistair Stead, Dan North](https://inviqa.com/blog/bdd-guide)
24+
- [Introducing BDD](https://dannorth.net/introducing-bdd/), by Dan North (2006)
25+
- [Wikipedia article on BDD](https://en.wikipedia.org/wiki/Behavior-driven_development)
26+
- [The beginner's guide to BDD (behaviour-driven development)](https://inviqa.com/blog/bdd-guide), by Konstantin Kudryashov, Alistair Stead, Dan North (2015)
2627
- [Behaviour-Driven Development](https://cucumber.io/docs/bdd/)
2728

28-
But enough theory, lets get our hands dirty. (You can find all the code of this tutorial here: https://github.com/JankariTech/flutterBDDexample)
29+
But enough theory, lets get our hands dirty. You can find all the code of this tutorial [here](https://github.com/JankariTech/flutterBDDexample).
2930

30-
## The feature files
31+
## Feature Files
3132

32-
For the start, you should have installed the flutter-tools stack and create a flutter test-drive app as explained in the [get-started document](https://flutter.dev/docs/get-started/test-drive?tab=androidstudio)
33+
To start, you should install the Flutter tools stack and create a Flutter test-drive app as explained in the [get-started document](https://flutter.dev/docs/get-started/test-drive?tab=androidstudio).
3334

34-
Inside the app folder create a folder called `test_driver` and inside another one called `features`. In `features` we will place all the Gherkin descriptions of the expected app behavior. So create here a file called: `increment_counter.feature`
35+
Inside the app folder create a folder called `test_driver`. And inside your new folder create another one called `features`. In `features` we will place all the Gherkin descriptions of the expected app behavior. Create a file in `features` called `increment_counter.feature` for this.
3536

3637
We start the feature file with a very general description of the feature:
3738
```gherkin
@@ -42,8 +43,7 @@ Feature: Increment Counter
4243
So that I notice if one is missing
4344
```
4445

45-
The first line is just a title of the feature; the other three lines should answer the questions [Who wants to achieve what and why with this particular feature](https://www.bibleserver.com/ESV/Luke15%3A4). If you cannot answer those questions for a particular feature of your app, then you actually should not implement that feature; there is no use-case for it.
46-
46+
The first line is just a title of the feature. The following three lines should answer the questions ["Who wants to achieve what and why with this particular feature?"](https://www.bibleserver.com/ESV/Luke15%3A4). If you cannot answer those questions for a particular feature of your app, then you should not implement that feature; there is no use case for it.
4747
Next, we have to describe the specific behavior of the app. For that, Gherkin provides 3 different keywords:
4848
- **Given** - prerequisites for the scenario
4949
- **When** - the action to be tested
@@ -57,15 +57,15 @@ Scenario: Counter increases when the button is pressed
5757
Then I expect the "counter" to be "10"
5858
```
5959

60-
Later we will add more scenarios to the app, the feature might be the same, but in different scenarios it might have to react differently.
60+
Later we will add more scenarios to the app. The feature might be the same, but in different scenarios it might have to react differently.
6161

6262
Now we can start the app and use our behavior description to check if it works as it should.
6363

64-
## Test-automation
64+
## Test Automation
6565

66-
Running manual tests from a description is nice, but not enough for us, we want to save time and reduce possible mistakes by running the tests automatically.
66+
Running manual tests from a description is nice, but not enough for us. We want to save time and reduce possible mistakes by running the tests automatically.
6767

68-
To interpret the Gherkin file and interact with the app we are using the `flutter_gherkin` package. Install it by placing `flutter_gherkin:` in the `pubspec.yaml` inside the `dev_depencencies` section.
68+
To interpret the Gherkin file and interact with the app we are using the `flutter_gherkin` package. Install it by placing `flutter_gherkin:` in the `pubspec.yaml` inside the `dev_dependencies` section as shown below:
6969
```yaml
7070
dev_dependencies:
7171
flutter_test:
@@ -107,15 +107,14 @@ Future<void> main() {
107107
..stepDefinitions = []
108108
..customStepParameterDefinitions = []
109109
..restartAppBetweenScenarios = true
110-
..targetAppPath = "test_driver/app.dart"
111-
..exitAfterTestRun = true; // set to false if debugging to exit cleanly
110+
..targetAppPath = "test_driver/app.dart";
112111
return GherkinRunner().execute(config);
113112
}
114113
```
115114

116-
That was all we need to do for the installation, now we have to tell the test-software what actually to do with our Given, When and Then steps.
115+
That was all we needed to do for the installation. Now we have to tell the test-software what to do with our Given, When, and Then steps.
117116
The library gives us some built-in steps that should work "out-of-the-box" but others we need to implement ourselves.
118-
In our example, the Then step is a built-in step but the Given and the When step have to be implemented. So let's do that. Inside `test_driver` create a folder called `steps` and in there create a file called `tap_button_n_times_step.dart` with the content:
117+
In our example, the Then step is a built-in step, but the Given and When steps have to be implemented. So let's do that. Inside `test_driver`, create a folder called `steps`, and in there, create a file called `tap_button_n_times_step.dart` with the following content:
119118
```dart
120119
import 'package:flutter_driver/flutter_driver.dart';
121120
import 'package:flutter_gherkin/flutter_gherkin.dart';
@@ -128,7 +127,7 @@ class GivenCounterIsSetTo extends Given1WithWorld<String, FlutterWorld> {
128127
@override
129128
Future<void> executeStep(String expectedCounter) async {
130129
final locator = find.byValueKey("counter");
131-
final actualCount = await FlutterDriverUtils.getText(world.driver, locator);
130+
final actualCount = await FlutterDriverUtils.getText(world.driver!, locator);
132131
expectMatch(actualCount, expectedCounter);
133132
}
134133
}
@@ -156,12 +155,12 @@ Next there is a variable called `pattern` with a regular expression, that is use
156155
Last there is a function `executeStep`. This function receives the parameters from the feature file and finally does all the hard work.
157156
In both cases it finds the element on the screen we want to interact with by using the `find.byValueKey()` method and then in the case of the Given step, gets the text of the element and checks if its as expected or, in the case of the When step, taps the button.
158157

159-
Similarly, our Then step (remember it's a built-in step) will use the same `find.byValueKey()` method to get the value and assert the content. If you are interested in the implementation, the step is defined in `flutter_gherkin-<version>/lib/src/flutter/steps/then_expect_element_to_have_value_step.dart`.
158+
Similarly, our Then step (remember, it's a built-in step) will use the same `find.byValueKey()` method to get the value and assert the content. If you are interested in the implementation, the step is defined in `flutter_gherkin-<version>/lib/src/flutter/steps/then_expect_element_to_have_value_step.dart`.
160159

161-
The issue now is that the example code does not have any keys defined in the widgets. The test-code would not be able to locate the elements.
160+
The issue now is that the example code does not have any keys defined in the widgets. The test code would not be able to locate the elements.
162161
So edit the `main.dart` file and add `key: Key('counter'),` to the counter widget and `key: Key('increment'),` to the button widget.
163162

164-
You could also use `find.byTooltip`, `find.Type` or `find.bySemanticsLabel`.
163+
As an alternative to `find.byValueKey`, you could also use `find.byTooltip`, `find.Type`, or `find.bySemanticsLabel`.
165164

166165
Next the new .dart file with the step definitions need to be imported in `app_test.dart`:
167166
`import 'steps/tap_button_n_times_step.dart';`
@@ -171,11 +170,11 @@ Additionally, every class we add in the step definitions we also have to registe
171170

172171
Remember: The step `Then I expect the "counter" to be "10"` is a built-in-step. So we don't need to write any code for it, it will look for a text-widget with the key `counter` and assert its value.
173172

174-
## run the tests
173+
## Run Tests
175174
1. connect your phone or start the emulator
176175
2. run `dart test_driver/app_test.dart`
177176

178-
after a while, you should see output like:
177+
After a while, you should see output in your console like:
179178
```console
180179
Running scenario: Counter increases when the button is pressed # ./test_driver/features/increment_counter.feature:5
181180
√ Given the counter is set to "0" # ./test_driver/features/increment_counter.feature:6 took 146ms
@@ -423,7 +422,7 @@ index 068f558..5e0d8d0 100644
423422

424423
## Conclusion
425424

426-
You have seen how to write Gherkin files and how to run them as automated tests for a flutter application.
425+
You have seen how to write Gherkin files and how to run them as automated tests for a Flutter application.
427426
I personally find flutter_gherkin a bit more complicated than other BDD frameworks, but it's possible, and I believe using BDD will improve the quality of your project greatly.
428427

429428
If you need any help with the test-coverage of your app, BDD or other test-related topics, please contact us [@JankariTech](https://www.jankaritech.com)

0 commit comments

Comments
 (0)