mirror of https://github.com/briot/gnatbdd
233 lines
9.0 KiB
ReStructuredText
233 lines
9.0 KiB
ReStructuredText
.. highlight:: gherkin
|
|
|
|
********
|
|
Features
|
|
********
|
|
|
|
An application's requirements are organized into features. Such a feature has a
|
|
name (for instance one feature we would use for GNATbdd itself would be "Find
|
|
features to run"), as well as a textual description. This description is only
|
|
meant for human readers, and is not used by the automatic tool.
|
|
|
|
The features are then further divided into one or more scenarios, which are
|
|
sometimes also called "tests". These will be discussed in the next section.
|
|
|
|
Syntax of the features file
|
|
===========================
|
|
|
|
The syntax of the features file is based on the one from Cucumber, which is
|
|
a BDD standard tool in the Ruby world. The grammar and syntax in those files
|
|
is voluntarily informal, since they are meant to be editable and readable
|
|
by people other than software developers.
|
|
|
|
As a result, this documentation is mostly based on examples. Let's start
|
|
with the first general layout for a file::
|
|
|
|
Feature: name of feature
|
|
high-level description
|
|
of what the feature does (plain English, not used by the tools)
|
|
|
|
Scenario: name of scenario
|
|
Given some precondition
|
|
And some other precondition
|
|
When I do some action
|
|
And I do some other action
|
|
Then I should see a specific result
|
|
And I see something else
|
|
But I do not see something else
|
|
|
|
There could be several **scenarios** within the **feature**. In fact, there
|
|
could also be several features in a given file, but this is not recommended in
|
|
general (this is an extension of the format used by cucumber).
|
|
|
|
The scenario is split into several **steps**, each of which start on a separate
|
|
line. The steps are introduced by one of several keywords, all shown in bold
|
|
in the example above. You can use any of the keywords for any of the steps, but
|
|
in general they have the following semantic:
|
|
|
|
* **Given** puts the system in a known state, before the user starts
|
|
interacting with it. Avoid talking about user interaction in givens. These
|
|
are similar to preconditions in programming languages.
|
|
|
|
For instance, a given would setup a database, log in a user, and so on.
|
|
|
|
* **When** describes the actions performed by the user, like clicking on
|
|
elements, providing input, and so on.
|
|
|
|
* **Then** observes the outcome of the actions. These observations should be
|
|
related to the business benefit that was described in the feature. The
|
|
observation should be on some kind of output that is something that comes out
|
|
of the system (report, user interface, message,...) and preferably not
|
|
something deeply buried in the system (use unit tests for those instead).
|
|
|
|
The example above indents each level of the description. This is not
|
|
strictly mandatory, but helps make the file more readable.
|
|
|
|
The keywords are case-sensitive, as is done in other BDD tools.
|
|
|
|
Comments
|
|
--------
|
|
|
|
A feature file can contain comments anywhere. These are lines whose first
|
|
non-blank character is '#'. The comment extends to the end of the line.
|
|
|
|
Tagging
|
|
-------
|
|
|
|
Features and scenarios can be tagged with one or more tags. These tags are
|
|
specific to your application and usage of GNATbdd. Primarily, they can be used
|
|
to run subsets of the whole set of scenarios. Here is an example::
|
|
|
|
@gui @editor @req-1-1
|
|
Feature: Opening an editor restores the previous location
|
|
|
|
@startup
|
|
Scenario: Restore open editors and their location on startup
|
|
Given a previous run that was editing foo.adb at line 5
|
|
When I start the application
|
|
Then I should see a window foo.adb at line 5
|
|
|
|
The tags of the feature automatically apply to its Scenarios
|
|
|
|
Other usage of tags could be to identify *slow tests* (with @slow) so that
|
|
their timeout is increased.
|
|
|
|
A tag can also be used to link a scenario to a *high-level requirement* in your
|
|
application, for instance @HLR-12-2.
|
|
|
|
Tags can also be used to identify *expected failures* (for instance @xfail), or
|
|
*work in progress* (for instance @wip).
|
|
|
|
|
|
Step configuration
|
|
------------------
|
|
|
|
Steps describe the actual actions to perform on the software, its input or its
|
|
output. In the examples above, we have seen various sentences used to describe
|
|
those actions. However, if we have to write a different sentence for every
|
|
little variation, this will end up being very difficult to maintain indeed.
|
|
|
|
So instead, the steps can be configured so that they apply to a wide variety of
|
|
scenario. For instance, going back the example on the editors above, there is
|
|
nothing specific in the test about the name *foo.adb* or the line *5*. We might
|
|
want to rerun a similar step on file *bar.adb* at line *10*. As we will see
|
|
when we discuss the definition of steps, this is of course doable.
|
|
|
|
But staying closer to the topic of the syntax, there are two other ways that
|
|
the steps can be configured, namely **multi-line strings** and **tables**.
|
|
|
|
* multi-line strings are convenient when the text to substitute contains
|
|
several lines. They can only be used as the last part of the step, as in
|
|
the following example::
|
|
|
|
Feature: Entering multiple lines of text in the editor
|
|
Scenario: Pressing the return key on the keyboaard
|
|
Given a blank editor
|
|
When I press the keys <a>, <enter>, <b>
|
|
Then the editor should contain
|
|
"""
|
|
a
|
|
b
|
|
"""
|
|
|
|
A multi-line string starts on a line of its own just after the step itself.
|
|
It starts with three double quotes (this is a notation that is familiar to
|
|
all Python developers), and ends on a similar line that contains double-quotes.
|
|
The double-quotes must appear on a line of their own.
|
|
|
|
We recommend indenting the quotes and their contains relatively to the step
|
|
itself to improve readability.
|
|
|
|
The lines between the quotes form the text that is used for the step itself.
|
|
Those lines are unindented by an amount equal to the indentation of the first
|
|
quotes line (so in the example above there will in fact be no whitespace
|
|
before 'a' and 'b' when we compare them to the actual output). If a line does
|
|
not start with enough white spaces, GNATbdd simply removes all leading white
|
|
spaces, but preserves the first non-white character.
|
|
|
|
* tables are another great way to provide input. They organize their data into
|
|
columns, which are interpreted by the step as it sees fit. Here an example::
|
|
|
|
Feature: Logging in on a website
|
|
Scenario: Logging with valid user account
|
|
Given the following users exist
|
|
| Name | Email | Phone |
|
|
| John | john@example.com | 1234 |
|
|
| Jack | jack@example.com | 5678 |
|
|
When I log in as "Jack"
|
|
Then I should see the home page
|
|
|
|
Leading and trailing spaces are ignored for each cell in the table.
|
|
|
|
Background scenario
|
|
-------------------
|
|
|
|
The givens in the last scenario above (providing the name of multiple users for
|
|
a web site) would need to be duplicated if we wanted another scenario that tests
|
|
logging in with an invalid user. Obviously, duplication is just as bad in tests
|
|
as it is in the code itself.
|
|
|
|
Instead, you can defined a background for the feature. It defines steps to be
|
|
performed before running each of the step in the scenario. For instance, the
|
|
feature above would be better written as::
|
|
|
|
Feature: Logging in on a website
|
|
Background:
|
|
Given the following users exist
|
|
| Name | Email | Phone |
|
|
| John | john@example.com | 1234 |
|
|
| Jack | jack@example.com | 5678 |
|
|
|
|
Scenario: Logging with valid user account
|
|
When I log in as "Jack"
|
|
Then I should see the home page
|
|
|
|
Scenario: Logging with invalid user account
|
|
When I log in as "Henry"
|
|
Then I should see the login page
|
|
|
|
|
|
The background must be defined before any scenario.
|
|
|
|
|
|
Scenario outlines
|
|
-----------------
|
|
|
|
We mentioned before that parts of the steps can be configured. For instance, we
|
|
could have a feature with the following two scenarios::
|
|
|
|
Feature: Testing addition in a calculator
|
|
Scenario: adding simple numbers
|
|
When I enter 5
|
|
And I add 12
|
|
Then I should get 17
|
|
|
|
Scenario: adding larger numbers
|
|
When I enter 105
|
|
And I add 1012
|
|
Then I should get 1117
|
|
|
|
The two scenarios are very similar, this is another case of duplication that
|
|
would best be avoided.
|
|
|
|
The feature file provides the notion of a **Scenario Outline**, which provides
|
|
text substitution to create multiple scenarios. Here is the example above
|
|
rewritten by taking advantage of this feature::
|
|
|
|
Feature: Testing addition in a calculator
|
|
Scenario Outline: adding simple numbers
|
|
When I enter <num1>
|
|
And I add <num2>
|
|
Then I should get <result>
|
|
|
|
Examples:
|
|
| num1 | num2 | result |
|
|
| 5 | 12 | 17 |
|
|
| 105 | 1012 | 1117 |
|
|
|
|
The **Examples** provide the values to substitute in the steps above. There
|
|
will be one scenario executed for each line in the examples.
|
|
|
|
For compatibility with other tools, the keyword **Examples:** can be replaced
|
|
with **Scenarios:**.
|