BDD girls battle JBehave vs Cucumber€£ Раннер тестов: Добавить tags...

Preview:

Citation preview

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

Recommended