New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tags #34
Add tags #34
Changes from 3 commits
0166799
2e01622
e5f2261
a42162d
d00a4e2
d0e915b
59b18da
18aa6ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
# Gherkin | ||
|
||
Gherkin is the language that Cucumber understands. It is a Business Readable, [Domain Specific Language](http://martinfowler.com/bliki/BusinessReadableDSL.html) that lets you describe software’s behaviour without detailing how that behaviour is implemented. | ||
|
||
Gherkin serves two purposes — documentation and automated tests. The third is a bonus feature — when it yells in red it’s talking to you, telling you what code you should write. | ||
|
||
Gherkin’s grammar is defined in the Treetop grammar that is part of the Cucumber codebase. The grammar exists in different flavours for many spoken languages (37 at the time of writing), so that your team can use the keywords in your own language. | ||
|
||
There are a few conventions. | ||
|
||
* Single Gherkin source file contains a description of a single feature. | ||
* Source files have `.feature` extension. | ||
|
||
## Gherkin Syntax | ||
|
||
Like Python and YAML, Gherkin is a line-oriented language that uses indentation to define structure. Line endings terminate statements (eg, steps). Either spaces or tabs may be used for indentation (but spaces are more portable). Most lines start with a keyword. | ||
|
||
Comment lines are allowed anywhere in the file. They begin with zero or more spaces, followed by a hash sign (`#`) and some amount of text. | ||
|
||
The parser divides the input into features, scenarios and steps. When you run the feature the trailing portion (after the keyword) of each step is matched to a Ruby code block called [Step Definitions](docs/step-definitions.md). | ||
|
||
A Gherkin source file usually looks like this | ||
``` | ||
1: Feature: Some terse yet descriptive text of what is desired | ||
2: Textual description of the business value of this feature | ||
3: Business rules that govern the scope of the feature | ||
4: Any additional information that will make the feature easier to understand | ||
5: | ||
6: Scenario: Some determinable business situation | ||
7: Given some precondition | ||
8: And some other precondition | ||
9: When some action by the actor | ||
10: And some other action | ||
11: And yet another action | ||
12: Then some testable outcome is achieved | ||
13: And something else we can check happens too | ||
14: | ||
15: Scenario: A different situation | ||
16: ... | ||
``` | ||
|
||
First line starts the feature. Lines 2–4 are unparsed text, which is expected to describe the business value of this feature. Line 6 starts a scenario. Lines 7–13 are the steps for the scenario. Line 15 starts next scenario and so on. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd avoid referring to line numbers unless we can display them in the margin somehow. Maybe GitBook has a plugin for that? |
||
|
||
Read more | ||
|
||
* [Feature Introduction](docs/gherkin.md#feature) – general structure of a feature | ||
* [Given/When/Then (Steps)](docs/gherkin.md#steps) | ||
|
||
## Feature Introduction {#feature} | ||
|
||
Every `.feature` file conventionally consists of a single feature. A line starting with the keyword Feature followed by free indented text starts a feature. A feature usually contains a list of scenarios. You can write whatever you want up until the first scenario, which starts with the word Scenario (or localized equivalent; Gherkin is localized for [dozens of languages](https://github.com/cucumber/cucumber/wiki/Spoken-languages)) on a new line. You can use tagging to group features and scenarios together independent of your file and directory structure. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Start by explaining that a Cucumber feature is a grouping of related scenarios, describing the same software feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please break long lines. Makes commenting easier. |
||
|
||
Every scenario consists of a list of steps, which must start with one of the keywords **Given, When, Then, But** or **And**. Cucumber treats them all the same, but you shouldn’t. Here is an example: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bold each word (without the comma inside). Saying people should treat the differently without explaining how isn't helpful (people are very confused about it).
|
||
|
||
``` | ||
Feature: Serve coffee | ||
Coffee should not be served until paid for | ||
Coffee should not be served until the button has been pressed | ||
If there is no coffee left then money should be refunded | ||
|
||
Scenario: Buy last coffee | ||
Given there are 1 coffees left in the machine | ||
And I have deposited 1$ | ||
When I press the coffee button | ||
Then I should be served a coffee | ||
``` | ||
|
||
In addition to a scenario, a feature may contain a background, scenario outline and examples. Respective keywords (in English) and places to read more about them are listed below. You can get a list of localized keywords with cucumber `--i18n [LANG]`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Capitalise keywords, and link to their section. Don't assume Ruby - we should rather generate docs with all the translations. |
||
|
||
| keyword | localized | more info see | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be a bullet list where you only use the last column. The first two columns aren't useful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove file path from links, use anchors only |
||
|-----------------|-------------------------|-------------------| | ||
| name | 'English' | | | ||
| native | 'English' | | | ||
| encoding | 'UTF-8' | | | ||
| feature | 'Feature' | [Feature](gherkin.md#feature) | ||
| background | 'Backgroound' | [Background](gherkin.md#background) | ||
| scenario | 'Scenario' | [Scenario](gherkin.md#feature) | ||
| scenario_outline| 'Scenario Outline' | [Scenario Outline](gherkin.md#background) | ||
| examples | 'Examples'/ 'Scenarios' | [Scenario Outline](docs/gherkin.md#background) | ||
| given | 'Given' | [Given/When/Then (Steps)](docs/gherkin.md#steps) | ||
| when | 'When' | [Given/When/Then (Steps)](docs/gherkin.md#steps) | ||
| then | 'Then' | [Given/When/Then (Steps)](docs/gherkin.md#steps) | ||
| and | 'And' | [Given/When/Then (Steps)](docs/gherkin.md#steps) | ||
| but | 'But' | [Given/When/Then (Steps)](docs/gherkin.md#steps) | ||
|
||
## Step definitions {#steps} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Step definitions don't belong in this document. Please move to a separate step-definitions.md doc, in a separate PR. |
||
|
||
For each step Cucumber will look for a matching **step definition**. A step definition is written in Ruby. Each step definition consists of a keyword, a string or regular expression, and a block. Example: | ||
|
||
``` | ||
# features/step_definitions/coffee_steps.rb | ||
|
||
Then "I should be served coffee" do | ||
@machine.dispensed_drink.should == "coffee" | ||
end | ||
``` | ||
|
||
Step definitions can also take parameters if you use regular expressions: | ||
|
||
``` | ||
# features/step_definitions/coffee_steps.rb | ||
|
||
Given /there are (\d+) coffees left in the machine/ do |n| | ||
@machine = Machine.new(n.to_i) | ||
end | ||
``` | ||
|
||
This step definition uses a regular expression with one match group – `(\d+)`. (It matches any sequence of digits). Therefore, it matches the first line of the scenario. The value of each matched group gets yielded to the block as a string. You must take care to have the same number of regular expression groups and block arguments. Since block arguments are always strings, you have to do any type conversions inside the block, or use Step Argument Transforms. | ||
|
||
When Cucumber prints the results of the running features it will underline all step arguments so that it’s easier to see what part of a step was actually recognised as an argument. It will also print the path and line of the matching step definition. This makes it easy to go from a feature file to any step definition. | ||
|
||
Take a look at [Step Definitions](docs/step-definitions.md) and the examples directory to see more. | ||
|
||
## Background {#background} | ||
|
||
A background section in a feature file allows you to specify a set of steps that are common to every scenario in the file. Instead of having to repeat those steps over and over for each scenario, you move them up into a Background element. There are a couple of advantages to doing this: | ||
|
||
A Background is much like a scenario containing a number of steps. The difference is when it is run. The background is run before each of your scenarios but after any of your Before [Hooks](hooks.md). | ||
|
||
Example: | ||
|
||
``` | ||
Feature: Change PIN | ||
#some feature description comes here | ||
|
||
Background: | ||
Given I have been issued a new card | ||
And I insert the card, entering the correct PIN | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you express these steps in past tense please? |
||
And I choose "Change PIN" from the menu | ||
|
||
Scenario: Change PIN successfully | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unindent these two scenarios to be at the same level as the background |
||
When I change the PIN to 9876 | ||
Then the system should remember my PIN is now 9876 | ||
|
||
Scenario: Try to change PIN to the same as before | ||
When I try to change the PIN to the original PIN number | ||
Then I should see a warning message | ||
And the system should not have changed my PIN | ||
``` | ||
|
||
You can have a single `Background` element per feature file, and it must appear before any of the `Scenario` or `Scenario Outline` elements. Just like all the other _Gherkin_ elements, you can give it a name, and you have space to put a multiline description before the first step. For example: | ||
|
||
``` | ||
Feature: Change PIN | ||
In order to be able to change it to something they can easily | ||
remember, customers with new bank cards need to be able to | ||
change their PIN using the ATM. | ||
|
||
Background: Insert a newly issued card and sign in | ||
Whenever the bank issues new cards to customers, they are supplied | ||
with a Personal Identification Number (PIN) that is randomly | ||
generated by the system. | ||
|
||
Given I have been issued a new card | ||
And I insert the card, entering the correct PIN | ||
... | ||
``` | ||
|
||
### Good practices for using Background | ||
|
||
* Don’t use `Background` to set up complicated state unless that state is actually something the client needs to know. | ||
* Keep your `Background` section short. | ||
* Make your `Background` section vivid. | ||
* Keep your scenarios short and don’t have too many. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good guideline, but it's not about Background, is it? |
||
|
||
## Doc Strings {#doc-strings} | ||
|
||
Doc strings just allow you to specify a larger piece of text than you could fit on a single line. For example, if you need to describe the precise content of an email message, you could do it like this: | ||
|
||
``` | ||
Scenario: Ban Unscrupulous Users | ||
When I behave unscrupulously | ||
Then I should receive an email containing: | ||
""" | ||
Dear Sir, | ||
Your account privileges have been revoked due to your unscrupulous behavior. | ||
Sincerely, | ||
The Management | ||
""" | ||
And my account should be locked | ||
``` | ||
|
||
Just like a [Data Tables](docs/gherkin.md#datatable), the entire string between the `"""` triple quotes is attached to the step above it. The indentation of the opening `"""` is not important, although common practice is to indent two spaces in from the enclosing step, as shown. | ||
|
||
The indentation inside the triple quotes, however, is significant: imagine the left margin running down from the start of the first """. If you want to include indentation within your string, you need to indent it within this margin. | ||
|
||
## Comments {#comments} | ||
|
||
As well as the description fields that follow Feature and Scenario keywords, Cucumber allows you to precede these keywords with comments. | ||
Like in Ruby, comments start with a `#` character. Unlike in Ruby, comments have to be the first and the only thing on a line (well, apart from whitespace). | ||
|
||
Here’s an example: | ||
``` | ||
# This feature covers the account transaction and hardware-driver modules | ||
Feature: Withdraw Cash | ||
In order to buy beer | ||
As an account holder | ||
I want to withdraw cash from the ATM | ||
|
||
# Can't figure out how to integrate with magic wand interface | ||
Scenario: Withdraw too much from an account in credit | ||
... | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Hooks | ||
|
||
Cucumber provides a number of hooks which allow us to run blocks at various points in the Cucumber test cycle. You can define them anywhere in your support or step definition layers, using the methods `Before` and `After`. Hooks are global by default, meaning they run for every scenario in your | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/layers/code/ |
||
features. If you want them to run for just certain scenarios, you need to tag | ||
those scenarios and then use a [tagged hook](hooks.md#tagged-hooks). | ||
|
||
## Scenario hooks | ||
|
||
`Before` hooks will be run before the first step of each scenario. They will run in the same order of which they are registered. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you make a h3 section for Before and After hooks? can you also describe how Before hooks are similar to Background, and when to use each one? (Before hooks are for techynthings like starting browsers or servers, starting database transactions etc, |
||
|
||
``` | ||
Before do | ||
# Do something before each scenario. | ||
end | ||
``` | ||
|
||
or like this: | ||
|
||
``` | ||
Before do |scenario| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We discourage this kind of logging - Cucumber's own formatters take care of that. Instead, show something more useful you can do with a Scenario object, like embedding something into the reports, like an image (typically from a screenshot) or text. |
||
# The +scenario+ argument is optional, but if you use it, you can get the title, | ||
# description, or name (title + description) of the scenario that is about to be | ||
# executed. | ||
Rails.logger.debug "Starting scenario: #{scenario.title}" | ||
end | ||
``` | ||
|
||
`After` hooks will be run after the last step of each scenario, even when there are failing, undefined, pending or skipped steps. They will run in the opposite order of which they are registered. | ||
|
||
``` | ||
After do |scenario| | ||
# Do something after each scenario. | ||
# The +scenario+ argument is optional, but | ||
# if you use it, you can inspect status with | ||
# the #failed?, #passed? and #exception methods. | ||
|
||
if scenario.failed? | ||
subject = "[Project X] #{scenario.exception.message}" | ||
send_failure_email(subject) | ||
end | ||
end | ||
``` | ||
|
||
`Around` hooks give you more power than Before and After hooks, allowing you to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Around hooks have caused a lot of pain, and it's a feature we're likely to deprecate and eventually remove. It only exists for ruby. I suggest not documenting it (and perpetuating its use). |
||
actually control how many times the scenario is run. An Around hook is passed | ||
two parameters: an object that represents the scenario and a block of code | ||
that, when called, will run the scenario: | ||
|
||
``` | ||
Around do |scenario, block| | ||
puts "About to run #{scenario.name}" | ||
block.call | ||
puts "Finished running #{scenario.name}" | ||
end | ||
``` | ||
|
||
`Around` hooks also accept tags, so you can restrict them to run for only some | ||
scenarios, just like `Before` and `After` hooks. One great trick we’ve seen them used for is to run the same scenario twice under different conditions, like this: | ||
|
||
``` | ||
Around('@run_with_and_without_javascript') do |scenario, block| | ||
Capybara.current_driver = Capybara.javascript_driver | ||
block.call | ||
Capybara.use_default_driver | ||
block.call | ||
end | ||
``` | ||
|
||
## Tagged hooks {#tagged-hooks} | ||
|
||
Both `Before` and `After` accept a tag expression, which you can use to selectively add the hook to only certain scenarios. | ||
|
||
``` | ||
@admin | ||
Feature: Delete Widgets | ||
... | ||
Before('@admin') do | ||
user = create_user(:admin => true) | ||
login_as user | ||
end | ||
``` | ||
|
||
Now, to run a scenario when you need to be logged in as an administrator, you just have to tag the scenario with `@admin`, and this code will automatically run before the steps of the scenario. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Tags | ||
|
||
Tags are a way to group Scenarios. They are `@`-prefixed strings and you can place as many tags as you like above `Feature, Scenario, Scenario Outline` or `Examples` keywords. Space character are invalid in tags and may separate them. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please backtick-quote each keyword independently |
||
|
||
Tags are inherited from parent elements. For example, if you place a tag above a `Feature`, all scenarios in that feature will get that tag. | ||
|
||
If you want to tag all the scenarios in a feature at once, just tag the `Feature` element at the top, and all the scenarios will inherit the tag. You can still tag individual scenarios as well. | ||
|
||
Similarly, if you place a tag above a `Scenario Outline` or `Examples` keyword, all scenarios derived from examples rows will inherit the tags. | ||
|
||
A `Scenario` or `Feature` can have as many tags as you like. Just separate them with spaces: | ||
|
||
``` | ||
@billing @bicker @annoy | ||
Feature: Verify billing | ||
``` | ||
|
||
You can tell Cucumber to only run scenarios with certain tags, or to exclude scenarios with certain tags. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is redundant with the 3 reasons you mention below. Remove this section? |
||
|
||
Cucumber can perform different operations before and after each scenario based on what tags are present on a scenario. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant. Remove? |
||
|
||
There are three main reasons for tagging scenarios: | ||
|
||
* _Documentation_: You simply want to use a tag to attach a label to certain | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the least interesting reason I think. Move down to the bottom. |
||
scenarios, for example to label them with an ID from a project management | ||
tool. | ||
* _Filtering_: Cucumber allows you to use tags as a filter to pick out specific scenarios to run or report on. You can even have Cucumber fail your test run if a certain tag appears too many times. | ||
* _Hooks_: Run a block of Ruby code whenever a scenario with a particular | ||
tag is about to start or has just finished. | ||
|
||
See [tagged hooks](hooks.md#tagged-hooks) for more details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add gherkin after backticks to get syntax highlighting