Что такое Gherkin? Как всё это работает, например с Cucumber-jvm? Какие обычные и специфичные features реализует фреймворк? Каковы best practices его использования? Когда вообще все это стоит применять?
Данный доклад интересен для тех кто желает ознакомится с BDD и вышеназванным фреймворком. Много практических примеров и несколько советов по использованию.
4. Gherkin
04.11.2014 / 4
Feature: Short summary title
As a common user
I want to be able to do something
So that I have a profit
Scenario: Particular case
Given some precondition
And some other precondition
When some action is done by user
And some other action
And yet another action
Then some testable outcome is achieved
And something else we can check happens too
Prepare Act Assert
5. Step Definitions & Runners
04.11.2014 / 5
package myprecious.tests.cucumber.steps;
public class CertainSteps {
@Given("^some precondition$")
public void step_definition() {
... //My code here
}
@When("^some action is done by user$")
public void some_action_is_done {
... //Some Selenium here
}
...
package myprecious.tests.cucumber.runners;
@RunWith(Cucumber.class)
@Cucumber.Options(
tags = {"~@skipped", "~@inProgress", "~@current"},
strict = true,
format = { "json:target/cukes.json"},
monochrome = true,
glue = {"myprecious.tests.cucumber.steps",
" myprecious.tests.cucumber.hooks"})
public class LetTehTestsOut {
}
regular expressions
only informative role
locations for test parts
“features” is separate one
@runMe
~@dontRunMe
reporting options
@tag
Scenario: Particular case
Given some precondition
7. Hooks
04.11.2014 / 7
Feature: Payment operations
@ui
Scenario: Make payment using current card
Given I have logged
And I have selected card
...
@service
Scenario: Get internal payment info
Given I have submitted payment :
...
public class TaggedHooks {
@Before("@ui")
public void startUpUi() {
//open browser ...
}
@After("@ui")
public void clearUi(Scenario scenario) {
if (scenario.getStatus().equals("failed")) {
byte[] screenshot = ((TakesScreenshot)driver).
getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
}
OR (“@ui, @service”)
AND ({“@ui”, “@service”})
only scenario status
if few, executed in backward order
~ works
here too
8. Feature: Card operations
Scenario: Change PIN successfully
Given I am on account main page
And I select my card from list
And I enter the correct PIN
When I change the PIN to 9876
Then the system should know my new PIN is 9876
Scenario: Transaction list
Given I am on account main page
And I select my card from list
And I enter the correct PIN
And card was used at least once
When I click info panel
Then list of transactions is shown
Scenario: Print card information
Given I am on account main page
And I select my card from list
And I enter the correct PIN
When I click print button
Then page with card information is shown
And it contains card account number
Background
04.11.2014 / 8
Feature: Card operations
Background: User selected a card
Given I am on account main page
And I select my card from list
And I enter the correct PIN
Scenario: Change PIN successfully
When I change the PIN to 9876
Then the system should know my new PIN is 9876
Scenario: Transaction list
Given card was used at least once
When I click info panel
Then list of transactions is shown
Scenario: Print card information
When I click print button
Then page with card information is shown
And it contains card account number
9. Examples
04.11.2014 / 9
Feature: User registration
Scenario: Tooltips for email registration
Given I am on quick registration form
When I fill "Email" field with ""
And I click somewhere else
Then I should see error message "Email cannot be blank"
When I fill "email" field with "darth.vader"
And I click somewhere else
Then I should see error message "Please input valid Email address"
When I fill "email" field with "admin@domain.com"
And I click somewhere else
Then I should see error message "Email has already been taken"
When I fill "password" field with ""
And I click somewhere else
Then I should see error message "Password cannot be blank"
When I fill "password" field with "asdf"
And I click somewhere else
Then I should see error message "Password is too short"
Feature: User registration
Scenario Outline: Tooltips for email registration
Given I am on quick registration form
When I fill "<field_name>" field with "<value>"
And I click somewhere else
Then I should see error tooltip "<error_message>"
Examples:
| field_name | value | error_message |
| Email | | Email cannot be blank |
| Email | luke.skywalker | Please input valid Email address |
| Email | admin@domain.com | Email has already been taken |
| Password | | Password cannot be blank |
| Password | asdf | Password is too short |
11. Usual variables
04.11.2014 / 11
When I select 28 as a "delivery date"
@When("^I select (d+) as a "(.+)"$")
public void stepDefA(int number, String controlName){
Given months "September,July,March" are checked
@Given("^months "(.+)" are checked$")
public void stepDefB(List<String> monthNames){
Given delivery date is “28-02-2014"
@Given("^delivery date is "(d{2}-d{2}-d{4})"$")
public void stepDefC(@Format("dd-MM-yyyy") Date today) {
Then payment is updated in DB2 database
@Then("^payment is updated in (DB2|Oracle) database$")
public void stepDefD(String dbName){
Then error dialog is shown again
@When("^error dialog is shown(?: again)?$")
public void stepDefE(){
12. Multiline text
04.11.2014 / 12
Then informational message is shown:
"""
Welcome to the Cosa Nostra card activation system.
=======
If you would like us to take care of these losers before they cause you
any trouble, please proceed to payment card information menu.
"""
Given I have a user account "Test Testersen"
When it is granted <Role> rights
And I submit a support request
Then I should receieve an email:
"""
Dear T. Testersen,
Unfortunately all our specialists are busy.
Please <Action> <Person> in order to get further help
with Your issue.
Thank You for using our service.
"""
Examples:
| Role | Action | Person |
| customer | call | customer support team |
| customer support | email | service operations team |
| service operations | brace | yourself |
@Then("^informational message is shown:$")
public void info_message_shown(String messageText) {
15. Integrate
04.11.2014 / 15
Maven failsafe plugin to launch the tests.
Test reports passed in json to Jenkins Cucumber report plugin.
16. Use the power
04.11.2014 / 16
Backgrounds, examples, regexps …
Given I am on the advanced search page
And I select "Endocrinology" from "Specialty"
And I choose "Yes" within "Accepts Insurance"
And I fill in "ZIP Code" with "90010"
And I select "5 miles" from "Search Radius"
When I press "Search"
When I search for a provider with the criteria:
| Provider Type | Doctor |
| Specialty | Endocrinology |
| Accepts Insurance | Yes |
| ZIP | 90010 |
| Search Radius | 5 miles |
When I search for a provider with the default criteria and:
| Specialty | Endocrinology |
| Accepts Insurance | No |
...
When I search for a provider with the default criteria
Then the search criteria should include:
| Provider Type | Doctor |
| Specialty | General |
| Accepts Insurance | Yes |
| ZIP | 90010 |
| Search Radius | 5 miles |
17. Use the power … of regexps?
04.11.2014 / 17
When I use email (?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-
9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[x01-x08x0bx0cx0e-x1fx21x23-x5bx5d-x7f]|[x01-
x09x0bx0cx0e-x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-
9](?:[a-z0-9-]*[a-z0-9])?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-
9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-
9]:(?:[x01-x08x0bx0cx0e-x1fx21-x5ax53-x7f]|[x01-x09x0bx0cx0e-x7f])+)])
When I am logged in
...
When I am logged in as "Joda"
@Then("^I am logged in$")
.* Anything or nothing
.+ Something
d* none or more digits
d+ some digits
"[^"]*" Something in quotes
an? Something optional
...
@When("^(?:I am logged|I log) in as an? "([^"]*)"$")
@Then("^(?:receipt has )?following payment (?:information|info) :$")
18. Choose your domain
04.11.2014 / 18
Scenario: User with valid credentials
Given an unauthenticated user
When the user tries to navigate to the welcome page
Then they should be redirected to the login page
When the user enters a valid name in the Name field
And the user enters the corresponding password in the Password field
And the user presses the Login button
Then they should be directed to the welcome page
• Security domain, user authentication
• Password based authentication domain
• UI widgets domain
• Domain of web assets
Scenario: User with valid credentials
Given an unauthenticated user
When the user tries to access a restricted asset
Then they should be directed to a login page
When the user submits valid credentials
Then they should be redirected back to the restricted content
• “WHAT” User authentication domain
• “HOW” Web based security domain
19. Declarative vs. Imperative
04.11.2014 / 19
How exactly to do it ?What should be done?
Scenario: Successful login
Given a user "Smith" with password "qwerty"
And I am on the login page
And I fill in "User name" with "Smith"
And I fill in "Password" with "qwerty"
When I press "Log in"
Then I should see "Welcome, Smith"
Background:
Scenario: Successful login
Given a user "Smith" with password "qwerty"
And I am on the login page
And I fill in "User name" with "Smith"
And I fill in "Password" with "qwerty"
When I press "Log in"
Then I should see "Welcome, Smith"
Scenario: User is greeted upon login
Given the user "Smith" has an account
When he logs in
Then he should see "Welcome, Smith"
Background: The user is logged in
Given a logged in user
Feature: The System
Scenario: Everything Works
Given the system exists
When I use it
Then it should work, perfectly
21. 04.11.2014 / 21
Don’t use Cucumber unless you live in the magic kingdom
of non-programmers-writing-tests (and send me a bottle of
fairy dust if you’re there!)
~ David Heinemeier Hansson
1. Non-developers are involved too
Product owner
Test engineer
? Test automation engineer
2. Executable specification
3. BDD, TDD
Specification, not script
Abstract, declarative
Shared language
Key examples
Collaboration tool
Jira (Behave Plug-in), Cucumber Pro, Relish . . .
Developer
22. Useful links and sources
Web
• github.com/cucumber/cucumber-jvm
• cukes.info/ – project page
• dannorth.net/archives/ – creator of BDD
• aslakhellesoy.com/ – framework creator
• agileforall.com/blog/ – usage examples
• cucumber.pro/ – Cucumber Pro + blog
Books
• The Cucumber Book – Wynne M, Hellesøy A, 2012
04.11.2014 / 22
Что общего между корнишонами** и мейнфреймами**?
Наверное все таки ничего. Но если вспомнить корнишон это Gherkin**, а с мейнфреймами тесно связан язык COBOL**
то мы получим два языка которые разделяет пятьдесят пять лет и которые были созданы с очень похожими целями.
Как и COBOL, а именно COmmon Business-Oriented Language, язык Gherkin был создан для того что бы
заполнить нишу между knowledge-holder’ами и разработчиками.
Сложно судить получилось ли это у COBOL, за время своего существования язык сталкивался со множеством проблем
(отсутствие модульности, структурности, нецелевое использование)
Подготовка – Действие – Проверка
Precondition (Условие) – Input – Output
Язык для определения спецификац ий используется практически во всех BDD Фреймворках
Ruby - Cucubmer
Java – Cucumber-jvm, Jbehave
Python – Behave
PHP – Behat
SpecFlow – C#
В общем всё что угодно что бы поработить мир и использоваться на проекте
Есть тест кейс с определённым шагом-действием
Для него в каком то классе есть аннотированный метод Step Definition
И все это дела запускает раннер
Всем понятно
Also scalar transformations
Cucumber-JVM's built-in scalar types are
numbers,
enums,
java.util.Date,
java.util.Calendar
and arbitrary types that have a single-argument constructor that is either a String or an Object
Если помните есть такие Examples, так вот
Screenshots are embedded in json as Base64 byte array
Cucumber tests are ran nightly or by launching the Jenkins job.
Bamboo (plugin), TeamCity (formatter) , TFS (SpecFlow uses Nunit)
Регекспы такое дело, можно такого сделать что захочется застрелиться
В какой степени использовать их решать вам (автоматизаторам), потому что им же их потом в основном и поддерживать
+ от password-based к OpenID, или centralized authentication system (CAS) model, или email ?
+ name выбирается DDL, radio buttons ?
+ обойти welcome page и попасть на дэшборд?
Разные stakeholder’ы для каждого домена, каждый меняется, сценарий _хрупкий_
Должно быть 2 домена:
- домен ЧТО, название, требование -- ЦЕЛЬ
- домен КАК , шаги, реализация -- желаемое ПОВЕДЕНИЕ приложения
2 человека для которых мы это пишем:
Тот кому необходима эта функиональность
Тот кто её реализует
Boring scenarios = bored stakeholders
Ханссон, Давид Хейнемейер
---Back to COBOL
One of the design goals for COBOL was to make it possible for non-programmers such as supervisors, managers and users, to read and understand COBOL code. As a result, COBOL contains such English-like structural elements as verbs, clauses, sentences, sections and divisions. As it happens, this design goal was not realized.
----
TDD, but where to start? BDD and PO will help
The idea was to combine automated acceptance tests, functional requirements and software documentation into one format that would be understandable by non-technical people as well as testing tools.
------
Outside-In
Your features should drive your implementation, not reflect it.