Behavior-Driven Development
с помощью Cucumber
Андрей Михайлов (lolmaus)
Frotnend-разработчик в Kaliber5
https://lolma.us
https://github.com/lolmaus
https://kaliber5.de
или как не подавиться огурцом
Behavior-Driven Development
assert.isEqual(actual, expected)
expect(actual).to.equal(expected)
actual.should.equal(expected)
Behavior-Driven Development
TDD
Пишем
падающий
юнит-тест
Пишем
код
Unit-тест
проходит
Рефакторим
Пишем падающий сценарий
Рефакторим
Сценарий проходит
Behavior-Driven Development
- Включает всех членов команды, в том числе непрограммистов:
- UX-специалист
- дизайнер
- менеджер
- представитель заказчика
- тимлид
- Вращается вокруг сценариев (user stories)
- Написаны на человеческом языке
- Описывают фичу с разных сторон
- Покрывают как основные,так и пограничные случаи
User stories для регистрации/логина
-
Посещение разделов:
- Анонимный пользователь посещает публичный раздел приложения, переходит с нее на страницу логина по ссылке.
- Анонимный пользователь посещает непубличный раздел приложения, и его перенаправляет на страницу логина.
- Залогиненный пользователь посещает непубличный раздел приложения.
- Залогиненный пользователь посещает страницу логина, и его перенаправляет в непубличный раздел приложения.
- Залогиненный пользователь посещает страницу регистрации, и его перенаправляет в непубличный раздел приложения.
-
На странице логина анонимный пользователь:
- вводит правильные логин и пароль, авторизуется и попадает в непубличный раздел приложения.
- вводит несуществующую комбинацию логин-пароль и видит соответствующую ошибку.
- пытается залогиниться с пустым логином, кнопка входа неактивна.
- пытается залогиниться с пустым паролем, кнопка входа неактивна.
-
На странице регистрации анонимный пользователь:
- успешно заполняет форму, авторизуется и попадает в непубличный раздел приложения.
- вводит недопустимый логин и видит ошибку (несколько вариантов), кнопка регистрации недоступна.
- вводит недопустимый пароль и видит ошибку (несколько вариантов), кнопка регистрации недоступна.
- вводит несоответствующую пару паролей и видит ошибку, кнопка регистрации недоступна.
- вводит всё правильно, пытается зарегистрироваться, но сервер отвергает пароль как уже занятый.
-
переходит на страницу восстановления пароля.
-
На странице восстановления пароля анонимный пользователь:
- вводит корректный имэйл, отправляет запрос и видит сообщение с просьбой проверить почту.
- вводит некорректный имэйл, кнопка отправки неактивна (несколько вариантов).
- вводит корректный имэйл, отправляет запрос, но сервер отвечает отказом, пользовател видит сообщение, что имэйл не используется.
Преимущества
сценариев и BDD
- Вскрывается истинный объем фич
- Более реалистичная оценка сроков
- Сценарии выполняют роль ТЗ
- Написаны на человеческом языке
- Служат источником правды для разрешения разногласий
- Разработчикам легко контролировать объем выполнения фич
- Сценарии фокусируются на нуждах пользователей
- Интегрируются с автоматическим тестированием
- Появился 10 лет назад как библиотека поверх RSpec на языке Ruby.
- Развился в полноценную методологию.
- Портирован на многие языки. Есть официальные порты от команды Cucumber и неофициальные аналоги.
- На JS есть официальный CucumberJS и неофициальный Yadda.
Feature-файл Cucumber
Feature: The blog.
Scenario: Visiting the blog with posts
Given there are 3 posts in the database
When I visit the blog page
Then I should see 3 posts
And I should not see the empty blog message
Scenario: Visiting an empty blog
Given there are 0 blog posts in the database
When I visit the blog page
Then I should see 0 posts
And I should see the empty blog message
- Separation of concerns
- Простота валидации
- Переиспользование кода (DRY)
- Читаемость тестов
- Упрощение поддержки кода тестов
- Интеграция в рабочий процесс
- Дисциплина
- Code coverage
- Унификация кода
- Скорость написания тестов
- Вовлечение всех членов команды
Преимущества Cucumber
Проблемы Cucumber
-
Библиотека имплементаций шагов растет бесконтрольно.
Ориентироваться в ней крайне трудно.
Проблемы Cucumber
- Библиотека имплементаций шагов растет бесконтрольно.
Ориентироваться в ней крайне трудно.
- Каждый шаг — это черный ящик.
Scenario: Viewing blog posts
Given there are 3 posts in the database
When I visit the blog
Then the title of the 1st post should be "Hello World"
Проблемы Cucumber
- Библиотека имплементаций шагов растет бесконтрольно.
Ориентироваться в ней крайне трудно.
- Каждый шаг — это черный ящик.
- Шаги имеют скрытые зависимости друг от друга.
When I expand the 2nd post
Then the expanded post should be expanded
Проблемы Cucumber
- Библиотека имплементаций шагов растет бесконтрольно.
Ориентироваться в ней крайне трудно.
- Каждый шаг — это черный ящик.
- Шаги имеют скрытые зависимости друг от друга.
- Использование CSS-селекторов контпродуктивно.
When I click on div p ul li:nth-child(2) a
Проблемы Cucumber
- Библиотека имплементаций шагов растет бесконтрольно.
Ориентироваться в ней крайне трудно.
- Каждый шаг — это черный ящик.
- Шаги имеют скрытые зависимости друг от друга.
- Использование CSS-селекторов контпродуктивно.
- Сложности с отладкой.
Решения
-
Ограничиваемся небольшим количеством универсальных шагов.
Например:
- клик
- ввод текста
- наведение мышкой
- чтение текста со страницы
- чтение текста из поле ввода
- выбор элемента из выпдающего списка
Решения
- Ограничиваемся небольшим количеством универсальных шагов.
- Выносим "правду" из имплементаций в сценарии.
Решения
- Ограничиваемся небольшим количеством универсальных шагов.
- Выносим "правду" из имплементаций в сценарии.
- Шаги ссылаются друг на друга в тексте сценариев, а не внутри имплементаций.
Было:
Then the 1st product should be selected
Стало:
Then ".product:nth-child(1)" should have HTML class "is-selected"
And I should see ".product:nth-child(1) .comments"
Было:
Given there are 2 posts in the database
# ...
Then the title of the 1st post should be "Hello world!"
Стало:
Given there are records of type "Post" in the database:
---------------------------------------------------
| id | title | body | authorId |
| "1" | "Hello world!" | "Lorem ipsum" | "1" |
| "2" | "Foo Bar" | "Lorem ipsum" | "1" |
---------------------------------------------------
# ...
Then the title of the 1st post should be "Hello world"
Решения
- Ограничиваемся небольшим количеством универсальных шагов.
- Выносим "правду" из имплементаций в сценарии.
- Шаги ссылаются друг на друга в тексте сценариев, а не внутри имплементаций.
- Используем только семантические селекторы с удобным, но намеренно ограниченным синтаксисом.
Было:
When I click on div p ul li:nth-child(2) a
Стало:
When I click on "[data-test-post]:nth-child(2) [data-test-title]"
4. Используем только семантические селекторы
[data-test-main-menu]
data-test-main-menu
main-menu
Main-Menu
4. Используем только семантические селекторы с удобным, но намеренно ограниченным синтаксисом
When I click [data-test-post]:nth-child(2) [data-test-expand-button]
4. Используем только семантические селекторы с удобным, но намеренно ограниченным синтаксисом
When I click the Expand-Button in the 2nd Post
Было:
Стало:
<div class="container">
<article data-test-post>
</article>
</div>
<div class="container">
<article data-test-post>
</article>
<article data-test-post>
</article>
</div>
<div class="container">
<article data-test-post>
</article>
<article data-test-post>
</article>
</div>
Проблема :nth-child()
2nd Post
[data-test-post]
:nth-child(2)
<div class="container">
<article data-test-post>
</article>
</div>
<div class="container">
<article data-test-post>
</article>
<article data-test-post>
</article>
</div>
<div class="container">
<article data-test-post>
</article>
<article data-test-post>
</article>
</div>
Решение: селектор :eq(2) из jQuery
2nd Post
[data-test-post]
:eq(2)
1
2
3
4
5
Решения
- Ограничиваемся небольшим количеством универсальных шагов.
- Выносим "правду" из имплементаций в сценарии.
- Шаги ссылаются друг на друга в тексте сценариев, а не внутри имплементаций.
- Используем только семантические селекторы с удобным, но намеренно ограниченным синтаксисом.
- Добавляем удобный вывод ошибок.
5. Добавляем удобный вывод ошибок
- Название шага
- Имплементация
- Assertion error
- Аргументы
- Стэктрэйс
Всем спасибо! ^_^
http://bit.ly/cucumber-ember-nn-2021
Секретный слайд
BDD и Cucumber (Ember NN part 2)
By Andrey Mikhaylov (lolmaus)
BDD и Cucumber (Ember NN part 2)
или как не подавиться огурцом
- 506