bdd girls battle jbehave vs cucumber€£ Раннер тестов: Добавить tags...
TRANSCRIPT
BDD girls battle JBehave vs Cucumber
1
‣ JBEHAVE ‣ Чернышева Анна
Герои битвы‣ CUCUMBER ‣ Ковалева Юлия
2
Процессы разработки и тестирования в Альфа Лаборатории
‣ SCRUM, BDD
‣ User Story пишет тестировщик или аналитик
‣ Автоматизатор развивает тестовый фреймворк
‣ Кросс функциональность команд
3
Стоит ли переписывать готовый фреймворк на новый ради нескольких преимуществ?
4
‣ Как решать похожие проблемы? Нужно ли решать?
‣ А если ничего не предпринимать
‣ Наши решения и выводы - это не панацея ...
‣ Максимум полезного в одном докладе
‣ Возможно мы что-то не учли...
Зачем нужна битва?
5
Selenium
JUnit
JAVA
HttpClient
Serenity
JBehave
Maven
6
Selenium
JUnit
JAVA
HttpClient
Serenity
JBehave
Maven
7
Selenium Selenide
JAVA
HttpClient
Serenity
JBehave
Maven Gradle
Rest Assured
Cucumber
JUnit
8
9
Написание сценариев
10
Раунд 1 Ключевые слова
Задача: Я хочу использовать текст шагов без привязки к ключевым словам
Given currency equals USD When currency equals USD
11
JBehave
12
Cucumber
"ru": { "and": [ "* ", "И ", "К тому же ", "Также " ]...
gherkin-languages.json
* = And | But | Given | When | Then
When currency equals USD Then currency equals USDGiven currency equals USD * currency equals USD
13
Cucumber
14
Cucumber Win
1 / 0
15
Раунд 2 Меньше повторов
Задача: Я хочу использовать одну реализацию шага для нескольких текстовых описаний.
When click on 'Cancel' button When click on 'Cancel' popup
16
JBehave
17
@When ("click on 'Cancel' {button | popup}") public void clickCancel() { //some magic here }
JBehave
18
@When("click on 'Cancel' button") @Alias("click on 'Cancel' popup") public void clickCancel() { //some magic here }
JBehave
19
@When("click on 'Cancel' button") @Alias("click on 'Cancel' popup") public void clickCancel() { //some magic here }@When("click on 'Cancel' button") @Aliases(values = {"click on 'Cancel' popup", "выполнено нажатие на кнопку 'Отмена'"}) public void clickCancel() { //some magic here }
Cucumber
20
@When("click on 'Cancel' (?:button|popup)") public void clickOnCancel() { //some magic here }
JBehave Win
1/1 0
21
Раунд 3 Формат даты
Задача: Я хочу, чтобы дата передавалась в шаг в определенном формате.
22
JBehave
@Given("ISO date format is $date") public void theIsoDateIs(@Named("date") Date date) { // ... }
Given ISO date format is 09/09/2009
23
JBehave
private ParameterConverter[] customConverters() { List<ParameterConverter> converters = new ArrayList<ParameterConverter>(); converters.add(new DateConverter(new SimpleDateFormat("yyyy-MM-dd"))); return converters.toArray(new ParameterConverter[converters.size()]); }
24
JBehave
private ParameterConverter[] customConverters() { List<ParameterConverter> converters = new ArrayList<ParameterConverter>(); converters.add(new DateConverter(new SimpleDateFormat("yyyy-MM-dd"))); return converters.toArray(new ParameterConverter[converters.size()]); }
25
Jbehave
@Override public Configuration configuration(){ return new MostUsefulConfiguration() .useParameterConverters(new ParameterConverters() .addConverters(customConverters())) .useStoryLoader(new LoadFromClasspath(this.getClass())) .useStoryReporterBuilder(new StoryReporterBuilder() .withDefaultFormats() .withFormats(Format.CONSOLE, Format.TXT)); }
26
Cucumber
27
Feature: Date format of current date
Scenario: Correct format * current date is 12.06.2014
Scenario: Incorrect format * current date is 2014-04-12
Cucumber
28
@Given("^current date is (.+)$") public void checkDateFormat(@Format("dd.MM.yyyy") Date date){ alfaScenario.write(date.toString()); this.date = date; }
Cucumber - падающий тест
29
ConversionException: Couldn't convert "2014-04-12" to an instance of: [class java.util.Date]
Cucumber Win
1 2/1
30
Раунд 4 Ключевые слова на разных языках
Задача: Владелец продукта хочет получать отчеты о тестировании на русском языке.
31
JBehaveСоздать properties файл с описанием ключевых слов Для русских слов i18n/keywords_ru.properties: Символы Unicode
32
@Override public Configuration configuration(){ ClassLoader classLoader = this.getClass().getClassLoader(); Keywords keywords = new LocalizedKeywords(new Locale("ru")); return new MostUsefulConfiguration() .useKeywords(keywords) .useStoryParser(new RegexStoryParser(keywords)) //... }
Определить ключевые слова в конфигурациях
JBehave
33
JBehave
34
Cucumber
35
import cucumber.api.java
Cucumber
36
Cucumber
37
Cucumber Win
2 3/1
38
Раунд 5 Аннотации жизненного цикла тестов
Задача: Организовать для тестов пред/пост обработчики: * делать скриншот при каждом фейле * очищать куки перед каждым тестом * установить размер экрана 1240*780
39
JBehave
@BeforeScenario
@BeforeScenario public void beforeEachScenario() { // ... } @BeforeScenario(uponType=ScenarioType.EXAMPLE) public void beforeEachExampleScenario() { // ... }
40
JBehave
@BeforeStory
@BeforeStory // @BeforeStory(uponGivenStory=false) public void beforeStory() { // ... } @BeforeStory(uponGivenStory=true) public void beforeGivenStory() { // ... }
41
JBehave
@AfterScenario public void afterAnyScenario() { // ... } @AfterScenario(uponOutcome=AfterScenario.Outcome.SUCCESS) public void afterSuccessfulScenario() { // ... } @AfterScenario(uponOutcome=AfterScenario.Outcome.FAILURE) public void afterFailedScenario() { // ... }
@AfterScenario
42
JBehave
@AfterStory
@AfterStory //@AfterStory(uponGivenStory=false) public void afterStory() { // ... } @AfterStory(uponGivenStory=true) public void afterGivenStory() { // ... }
43
JBehave
@BeforeStories @AfterStories
@BeforeStories public void beforeCollectionOfStories() { // ... } @AfterStories public void afterCollectionOfStories() { // ... }
44
Обратный порядок...
@BeforeScenario
@BeforeScenario public void beforeEachScenario() { // ... } @BeforeScenario(uponType=ScenarioType.EXAMPLE) public void beforeEachExampleScenario() { // ... }
45
JBehave
@BeforeStory
@BeforeStory // @BeforeStory(uponGivenStory=false) public void beforeStory() { // ... } @BeforeStory(uponGivenStory=true) public void beforeGivenStory() { // ... }
46
JBehave
@AfterScenario public void afterAnyScenario() { // ... } @AfterScenario(uponOutcome=AfterScenario.Outcome.SUCCESS) public void afterSuccessfulScenario() { // ... } @AfterScenario(uponOutcome=AfterScenario.Outcome.FAILURE) public void afterFailedScenario() { // ... }
@AfterScenario
47
JBehave
@AfterStory
@AfterStory //@AfterStory(uponGivenStory=false) public void afterStory() { // ... } @AfterStory(uponGivenStory=true) public void afterGivenStory() { // ... }
48
JBehave
@BeforeStories @AfterStories
@BeforeStories public void beforeCollectionOfStories() { // ... } @AfterStories public void afterCollectionOfStories() { // ... }
49
Cucumber
Всего 2 аннотации в наличии: @After и @Before
Дополнительные настройки:
@After("dataUI") @Before(value = "unstable", timeout = 1000, order = 3)
50
Cucumber - Не запутайся!
@Before(order = 3) @Before(order = 1)
@After(order = 3) @After(order = 1)
51
Документация
?
Cucumber - Не запутайся!
@Before(order = 3) @Before(order = 1)
@After(order = 3) @After(order = 1)
52
Документация
Cucumber Scenario
53
@AfterScenario(uponOutcome=AfterScenario.Outcome.FAILURE) public void afterFailedScenario()
JBehave
А как в Cucumber?
Cucumber Scenario
54
@AfterScenario(uponOutcome=AfterScenario.Outcome.FAILURE) public void afterFailedScenario() JBehave
интерфейс cucumber.api.Scenario ...
JBehave Win
3/2 1
55
Раунд 6 Заготовки или предусловия
Задача: Было бы удобно выполнять некую последовательность шагов перед схожими по логике сценарями.
Например: Хотим рисовать несколько кошек разных пород или окрасов.
56
JBehave
!-- Предусловие ко всему .story файлу GivenStories: path/to/openPaintAndCreateNewFile.story
Scenario: Drawing a munchkin cat Given file is opened When the user draws cat with short legs Then they should see a munchkin cat
Scenario: Drawing a maine coon cat ***
57
JBehave
!-- Предусловие ко всему .story файлу GivenStories: path/to/openPaintAndCreateNewFile.story
Scenario: Drawing a white munchkin cat !-- Предусловия к конкретному сценарию GivenStories: path/to/selectWhiteBrush.story Given file is opened When the user draws cat with short legs Then they should see a munchkin cat
58
JBehave
Scenario: Drawing a munchkin cat specifying cats color using the rows of the Examples table
Scenario: Drawing a munchkin cat GivenStories: selectBrush.story Given file is opened When the user draws cat with short legs Then they should see a 'Color' munchkin cat
Examples: |Color| |white| |gray |
59
Cucumber
60
Feature: Cats drawing Background: Sketch preparing Given blank area for drawing When choose a color of line When choose a line thickness
Scenario Outline: Draw a cat When draw cat "<type>" Then coat color is <color> Examples: | type | color | | british | grey | | persian | different |
Cucumber
61
Feature: Cats drawing Background: Sketch preparing Given blank area for drawing When choose a color of line Scenario Outline: Draw a cat When draw cat "<type>" Then cat is appeared Examples: | type | | british |
Scenario Outline: Change a color When color was changed to <color_name> Examples: | colorname | | red |
Cucumber
62
# language: en
Feature: Folders names Scenario Outline: Folders names for the Credits application Given <conditional_step> When <go_to_folder> Then the folder name <folder_name> is appeared Examples: | conditional_step | go_to_folder | folder_name | | application Credits is started| - | Credits | | main page is appeared | go to Credits| Credits |
Cucumber Win
3 4/2
63
Раунд 7 Наборы тестов
Задача: Я хочу запускать наборы смоук и регрессионных тестов отдельно
64
default meta matcher :== ([+|-] [name] [value pattern])+
testAnnotations.properties smoke=+smokeTests -skip
JBehave
65
JBehave
Meta: @smokeTests
Scenario: Some smoke scenario Given the user is on home page When the user makes base action Then the user sees result
./gradlew clean test -PtestType=smoke
66
JBehave @skip
Meta: @skip
Scenario: Some unstable scenario Given the user is on home page When the user makes base action Then the user sees result
67
Cucumber
‣ Запуск тестов: ./gradlew clean test -Dcucumber.options=”--tags @smoke” ‣ Раннер тестов: Добавить tags ={"@smoke"} в аннотацию @CucumberOptions
68
Feature: Create request for Credit @smoke Scenario: Create credit request for sum equals 0 rubles Given application Credits is started
@regress Scenario: Create credit request for sum equals 100 rubles Given application Credits is started
Cucumber
‣ -Dcucumber.options=”--tags @smoke --tags @regress” - срабатывает условие И
‣ Альтернатива: tags ={"@smoke","@regress"}
69
Cucumber
‣ -Dcucumber.options=”--tags @smoke,@regress” - срабатывает условие ИЛИ
‣ Альтернатива: tags ={"@smoke,@regress"}
‣ -Dcucumber.options=”--tags @smoke --tags @regress” - срабатывает условие И
‣ Альтернатива: tags ={"@smoke","@regress"}
70
Cucumber
71
А если чуть сложнее настройку сделать ...
@smoke Feature: Create request for Credit @smoke Scenario: Create credit request for sum equals 0 rubles Given application Credits is started
@regress Scenario: Create credit request for sum equals 100 rubles Given application Credits is started
Cucumber
‣ -Dcucumber.options=”--tags @smoke --tags ~@regress” - срабатывает условие И и ИСКЛЮЧЕНИЕ
‣ Альтернатива: tags ={"@smoke", "~@regress"}
72
Cucumber Win
4 5/2
73
Раунд 8 Нереализованные шаги
Задача: У меня еще не реализован шаг, но я хочу запускать тест и чтобы он не падал.
74
JBehave
@Given("page is opened with title $title") @Pending public void pendingMethod(String title) { // not yet implemented }
@Pending keyword
75
Cucumber
@Pending можно навешивать на класс-исключение
Тестовые методы могут кидать исключение: throw new PendingException();
В консоли:
Then step was not written # AccountsSteps.notImplementedStep() cucumber.api.PendingException: TODO: implement me
76
Cucumber
77
Cucumber Win
5 6/2
78
Раунд 9 Кроссбраузерность
Задача: Я хочу организовать кроссбраузерное тестирование без использования сторонних инструментов помимо BDD библиотеки.
79
JBehave
Поддерживаются браузеры в JBehave: PropertyWebDriverProvider.class
Поддерживается системной переменной browser
public enum Browser { CHROME, FIREFOX, IE, ANDROID, HTMLUNIT }
80
Cucumber
‣ Нет реализации запуска тестов в разных браузерах
‣ Придется писать свою фабрику драйверов или же воспользоваться сторонними инструментами. Например, Selenide
./gradlew clean test -Dbrowser=chrome
chrome ie edge firefox safari
81
JBehave Win
6 / 3 2
82
Раунд 10 Тестовые данные отдельно от тестов
Задача: Я хочу одни и те же тестовые данные использовать для многих кейсов. Мне будет удобно хранить их в одном месте в файле. Возможно даже удаленно.
83
JBehave
Scenario: The Examples tables could be loaded from external resources Given page is opened with <title> When user clicks on button <button> Then the alert status should be <status> Examples: org/project/examples/stories/allert.table
84
Простой и понятный способ
Cucumber
85
JBehave Win
6 / 4 3
86
Отчеты о тестировании
87
Раунд 11 Удобный отчет о тестировании
Задача: Я хочу предоставить своей команде удобный отчет без лишней информации и без подключения дополнительных библиотек.
88
JBehave
89
JBehave + Serenity
90
91
JBehave + Serenity
92
JBehave + Serenity
Cucumber
93
Cucumber минимум полезной суммарной информации
94
95
Cucumberможно прикреплять скриншоты/логи
96
Cucumber Win
6 7 / 4
97
Раунд 12 Запуск тестов параллельно
Задача: Я хочу распараллелить запуск тестов, чтобы уменьшить время выполнения регрессионого тестирования.
98
Jbehave
JBehave & Cucumber - отдельный доклад
Embedder для JBehave - и плагин не нужен!
99
Cucumber
Для Maven есть реализация на gitHub: https://github.com/temyers/cucumber-jvm-parallel-plugin
Для Gradle мы ничего подходящего не нашли и написали свой: https://github.com/alfa-laboratory/cucumber-parallel-test-gradle-plugin
100
JBehave Win
7 / 5 4
101
Dependency Injection
102
JBehave + Spring
@RunWith(SpringAnnotatedEmbedderRunner.class) @Configure() @UsingEmbedder(embedder = Embedder.class, generateViewAfterStories = true, ignoreFailureInView = true) @UsingSpring(resources = {"org/examples/spring/steps.xml" })
public class EmbedderUsingSpring extends InjectableEmbedder { //some magic here }
103
Cucumber + Guice
104
1) требуется добавить в build.gradle: compile group: 'com.google.inject', name: 'guice', version: '<guice.version>'
2) помним про три аннотации: @Inject @ScenarioScoped @Singleton
JBehave Win
7 / 6 5
105
Page Object
106
JBehave + Serenity PageObject
@DefaultUrl("https://www.wikipedia.org/") public class HomePage extends PageObject {
@FindBy(name="search") private WebElementFacade searchElement;
@FindBy(name="go") private WebElementFacade goButton;
public void enterKeywords(String keyword) { searchElement.type(keyword); } }
107
JBehave + Serenity PageObject
108
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
109
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
110
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
111
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
112
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
113
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
114
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
115
‣ Работа с WebDriver ‣ Работа с переменными среды ‣ Работа с ожиданиями (появление, наличие данных) ‣ Взаимодействие с элементами страницы ‣ Работа с загрузкой файлов ‣ Организация базовых проверок ‣ Angular и Ajax ожидания
Cucumber + Selenide
@Name("Login page") public class LoginPage extends AlfaPage {
@FindBy(css = "div[eventproxy$=\"WPanel1_WImage1\"]") @Name("logo") private SelenideElement loginLog;
@FindBy(css = "div[eventproxy$=\"lblGotoNewDshb\"]") @Name("newBankLink") @Optional private SelenideElement newBank; }
116
Dead Heat
7 8 / 7 6
117
Cucumber — победитель!
118
Заключение
Jbehave мощный, тяжелый инструмент
Cucumber модный, молодежный, стремительно развивающийся
Свои фишки и ограничения есть у каждого, также как и решения для быстрого старта проекта
Выбор остается за вами: классика или модерн, сложности есть везде, главное азарт!
119
120
Контакты
‣ Чернышева Анна ‣ skype Ganna_Chernyshova ‣ facebook anna.chernyshova.79
‣ Ковалева Юлия ‣ skype juliana_kov
121