Опыт использования BDD


    Около семи лет назад Dan North в своей статье описал практическое применение BDD подхода, который позволяет сделать процесс разработки более понятным и управляемым путем налаживания внутренних коммуникаций. Индустрия с каждым днем проявляет всё больший интерес к этой методологии, нацеленной на продуктивное взаимодействие стандартных команд типа «аналитика-разработка-тестирование».


    Однако, сейчас лишь малая часть компаний решается на использование BDD. Почему?


    Итак, давайте разберемся. BDD (Behaviour Driven Development — «Разработка через поведение») — гибкая методология, тесно связанная с TDD (Test Driven Development — "Разработка через тестирование"). По опыту, даже матерые тестировщики зачастую не видят разницы между этими методологиями. Действительно, на первый взгляд ее трудно вычленить: оба подхода предполагают написание документации и тестов до старта этапа разработки. А различие вот в чем: в BDD для описания тестов требуется использование естественного языка, понятного каждому участнику проекта, чтобы, фактически, объединить постановку задачи, тесты и документацию воедино. Другими словами, определяется DSL (специфичный предметно-ориентированный язык), потом составляется стандартный ограниченный набор фраз, описывающих поведение нужных элементов. Затем с их помощью разрабатывается сценарий использования новой функциональности, который будет понятен всем.


    Давайте один раз увидим разницу, и она станет очевидной:



    Мы еще коснемся этого примера, а для начала давайте посмотрим на все разнообразие методологий, которые на данный момент имеют ненулевую актуальность.


    Сравним несколько методологий


    Диаграмма ниже показывает сравнение трех подходов: TDD, TLD (Test Last Development) и BDD:



    • Когда мы работаем по методологии BDD, автотестирование и составление спецификации сопровождает каждый этап цикла разработки ПО, что обеспечивает постоянную актуальность автотестов и документации.
    • Методологии TDD и ATDD (Acceptance Testing) объединены на диаграмме в один блок, т.к. пишутся на этапе аналитики. Как уже было сказано выше, TDD основан на написании тестов до разработки функционала. Разработчик должен написать тесты для того, чтобы написать функционал под тест.
    • TLD (Test Last Development) включает тестирование после реализации функционала.
    • BDD универсален и может включаться на любом этапе разработки.

    На второй диаграмме изображено вовлечение участников процесса разработки в написание сценариев.



    • В BDD к тестам на любом этапе может подключиться любой член команды, например, аналитик, бизнес пользователь, разработчик и тестировщик, так как тесты понятны всем участникам процесса.
    • BDD еще полезен тем, что не нужно тратить много времени на написание разного рода документации. При классической схеме разработки нужны, как минимум, спецификации и тестовые сценарии, которые обычно пишут разные люди. В BDD спецификация является тестовым сценарием, одновременно являясь и автотестом. Тестировщикам не нужно писать отдельную тестовую документацию — за них это уже сделал аналитик, написавший спецификацию из конструкций естественного языка (которая читаема и понятна любому члену команды).

    Несомненно, BDD — это хороший инструмент, позволяющий достичь качества продукта. Тесты и документация пишутся быстрее. Для бизнеса проект становится более прозрачным, благодаря конструкциям естественного языка, понятным любому человеку, далекому от программирования.


    Это о плюсах. Тем не менее, как уже было сказано, несмотря на большое количество плюсов, мало кто эту методологию внедряет.


    BDD всем хорош, но почему его не используют?


    Ответ прост: это долго и дорого. С этим утверждением согласятся большинство IT компаний. И поначалу мы не были исключением. BDD неудобен хотя бы тем, что требует привлечения специалистов тестирования уже на этапе проработки требований.


    BDD переворачивает с ног на голову классическую схему ведения разработки (TLD). Она плохо реализуема, потому что это сложно. Удлиняется цикл разработки.


    BDD — это несомненно способ достичь качества. Но не все готовы платить временем и специалистами за это качество.


    Однако, что делать, если BDD все же хочется внедрить?


    Можно попробовать использовать готовые фреймворки. Например Cucumber, Squish, Yulup.


    Основная проблема сложности BDD не в процессе, а в реализации и существующих инструментах. Возьмем в качестве примера WEB разработку корпоративной информационной системы. Имея web реализацию мы сталкиваемся с WebDriver'ом являющимся в данный момент стандартом при автоматизации приложений, работающих в веб браузере. Он обладает довольно большими возможностями. Для учитывания различных кастомизаций элементов страницы необходимо придумывать варианты обращения к ним. И тут для облегчения разработки теста на помощь приходят различные библиотеки (Selenide, и др.), что создает свою экосистему, которую нужно знать. Для работы с WebDriver нужен программист либо тестировщик-автоматизатор, т.к. все реализуется с помощью кода и хитрых конструкций.


    Начало работы с BDD фреймворком — сложно и долго


    Наше внимание остановилось на инструменте под названием Gauge. Это гибкий и легковесный фреймворк, распространяющийся по свободной лицензии. Признаться честно, мы не особо изучали альтернативы, т.к. использование Gauge было настойчиво продиктовано нашим заказчиком.


    В Gauge тесты пишутся в файлах спецификаций (файлы с расширением .spec). Спецификация содержит шаги теста, написанные на естественном языке. Эти шаги имплементируются на каком-либо языке программирования (у нас был использован язык программирования Java). При имплементации шагов важно соблюдение Naming Convention как в именах файлов сценария и реализации, так и в именах методов реализации и шагов сценария, они должны полностью совпадать. Дополнительную гибкость этому инструменту даёт то, что шаги могут иметь параметры.


    Gauge позволил нам использовать плюсы BDD. Однако мы все равно столкнулись с проблемами, которые заключаются в сложности реализации: проблемы инструментария и внедрения процесса.


    Оказалось, что привлечение тестировщиков на раннем этапе плохо сказывается на конечном результате. Увеличивается время на разработку тестов. При использовании любого фреймворка требуются большие усилия тестировщика, который, несомненно, хорошо должен владеть и программированием. Поначалу процесс работы со сценарием был следующим: аналитик рассказывал тест тестировщику, а записывал его технический писатель. Пока тестировщик разбирался с программной реализацией, изменялся смысл тестируемой функциональности. Тут сказывается разделение точки входа, а она должна быть одна, по итогу процесс разделяется и превращается в “обычный” процесс, от которого как раз и хотелось уйти. Т.е. точка входа разделилась, коммуникации расползлись, тестировщик ушел с головой в имплементацию теста, технический писатель понял как-то по своему, а аналитик уже и свои доки переписал и передумал, разработчик же вообще ушел в “свой мир” ).


    Много времени у тестировщика уходило на код. А ведь еще тот же тестировщик должен был продумать поиск элементов на странице. Ситуация напоминала известную детскую игру: “Испорченный телефон”. Возникал коллапс. И мы решили: BDD будет работать только в том случае, если тесты смогут писать аналитики. Нужно снизить трудоемкость написания тестов, упростить их. Но для этого нужно существенно упрощать интерфейсы тестирования. Инструменты тестирования, реализация процесса в совокупности со всеми подходами и библиотеками должны быть проще.


    Работа тестировщика вначале выглядела следующим образом:


    1. Изучение документации, если она есть;
    2. Составление чеклиста;
    3. Ad-hoc тестирование;
    4. Составление тест плана;
    5. Уточнение картины мира у аналитика;
    6. Уточнение картины мира у разработчика;
    7. Если все срослось, написание тестовой документации, параллельно с тестированием;
    8. Ожидание фикса багов, тестирование багов;
    9. Описание страниц, контролов, поиск элементов на странице используя Web-Driver. Поиск того что уже реализовано в системе тестов;
    10. Написание логики теста;
    11. Релиз;
    12. Support bug/Regress bug;
    13. Обновление спецификации;
    14. Фикс бага;
    15. Обновление автотеста, обновление большого количества изменившихся контролов;
    16. Релиз;

    17. Пункты, выделенные курсивом, (1, 5, 6, 7, 9, 13, 15) приводят к временным затратам. Их можно и нужно оптимизировать.

    Этот список кратко проиллюстрирован на диаграмме процесса разработки:



    Наша компания специализируется на проектах с веб реализацией интерфейсов. Исходя из этого, мы используем инструмент Web Driver для взаимодействия с веб браузером.


    Де-факто, Selenium Web Driver является стандартом, и он используется для описания веб объектов на любых фреймворках, в том числе Gauge, jUnit, библиотек Masquerade и других. Гибкости у него много для разных задач, что создает излишнюю трудоемкость в локально-типовых задачах. Нам нужно найти решение для уменьшения трудоемкости.


    Для примера покажем на схеме — как связаны Selenium Web Driver, фреймворк Gauge, библиотека Masquerade, язык программирования Java.



    В этой схеме можно вместо BDD фреймворка поставить jUnit, TestNG или любой другой, любая связка будет работать, в зависимости от потребностей. Selenium и Masquerade останется, язык программирования можно изменить.


    Ускорение процесса написания кода — подключение Masquerade


    В нашей компании разработка ведется на платформе CUBA. И специально для этой платформы был разработан инструмент для автотестов: Masquerade — библиотека, которая предоставляет лаконичный и удобный API для работы с кодом при имплементации тестов с использованием WebDriver. Эта библиотека работает над Selenium Web Driver, дружит с selenide и любыми фреймворками.


    В CUBA проектах каждый элемент веб страницы содержит cuba-id, который не меняется. В CUBA используется компонентный подход, а библиотека Masquerade упрощает взаимодействие с элементами веб страницы. Библиотека умеет совершать действия с элементами веб страницы, реализованными с помощью CUBA, более простым образом. Поэтому при поиске элементов на странице не нужно использовать громоздкие конструкции с XPath, как было раньше:


    $(new By.ByXPath("//*/div/div[2]/div/div[2]/div/div/div[3]/div/div/div[3).click();

    Или более лаконичные конструкции на Java, которые, тем не менее, по-прежнему громоздки:


    private static void click(String cssClass, String caption) {
                 $(By.cssSelector(cssClass)
                 .$(byText(caption))
                .closest(".v-button")
                .click();
    }

    После подключения библиотеки Masquerade описание вложенного контрола выглядит просто и к нему легко обратиться. Можно даже не искать контрол на странице, т.к. в проекте он уже есть. Приведем пример описания кнопки для формы авторизации в приложении:



    В коде страницы нам виден четко узнаваемый элемент cuba-id=”loginButton”



    Опишем кнопку, используя библиотеку Masquerade:


    @Wire(path = {"WebHBoxLayout", "loginButton"})  
    private Button loginButton;

    Простой вариант реализации теста на фреймворке jUnit — блок авторизации, который выполняется перед каждым тестом:


    @Before
    public void loginAdm() {
       Tests loginTest = _$(Tests.class);
       loginTest.login();
    }

    А в теле метода login следующий код:


    LoginWindow loginWindow = _$(LoginWindow.class);
    assertNotNull(loginWindow.getLoginField());
    loginWindow.getLoginField()
           .shouldBe(EDITABLE)
           .shouldBe(ENABLED);
    loginWindow.loginField.setValue("admin");
    loginWindow.passwordField.setValue("admin");
    loginWindow.rememberMeCheckBox.setChecked(true);
    loginWindow.loginButton().click();

    При этом самое важное — то, как мы описываем страницу, как мы обращаемся к элементам. Описание страницы LoginWindow:


    public class LoginWindow extends Composite<LoginWindow> {
       @Wire(path = {"loginField"} )
       private TextField loginField;
       @Wire(path = {"passwordField"} )
       private PasswordField passwordField;
       @Wire(path = {"rememberMeCheckBox"} )
       private CheckBox rememberMeCheckBox;
       @Wire(path = {"loginFormLayout", "loginButton"}   )
       private Button loginButton;
       }

    Поиск элементов — это лишь часть возможностей библиотеки Masquerade. Обращение к элементам веб страницы позволяет совершать различные действия с этими элементами. Например, можно выбрать элемент из выпадающего списка:


    getMaxResultsLayout().openOptionsPopup().select("5000")

    Или отсортировать таблицу:


    Table tb1 = client.getPaymentsTable();
    tb1.sort("column_year", Table.SortDirection.ASCENDING);

    Список некоторых действий с таблицей смотрите на скриншотах ниже:





    Использование Masquerade значительно упростило написание тестов, теперь, чтобы написать тест для новой функциональности, нужно:


    1. С помощью Masquerade описать страницу — это делается легко и не требует особых навыков программирования.
    2. Собрать в одном классе все страницы, которые используются при проверке функционала.
    3. Из готовых конструкций естественного языка собрать тестовый сценарий (подставив туда названия нужных элементов), то есть написать Gauge-спецификацию.

    Интегрируем Masquerade и Gauge


    До использования BDD, применялся подход TLD и для работы с ним мы также оптимизировали процесс написания кода тестов. Использовали связки jUnit/TestNG + WebDriver+Selenide+Masquerade.


    Теперь, для того, что бы работать с Gauge, добавляем соответствующий плагин в intellij IDEA. После этого появится возможность создавать новый тип тестов — Specification.


    Теперь создаем спецификацию (сценарий) и имплементируем шаги, используя возможности WebDriver, Masquerade и Java.



    Кликаем на шаг сценария и переходим в имплементацию:



    В имплементации можно использовать уже существующий метод login().


    Как же выглядит это совершенство?


    Вспомним пример, который мы рассматривали в самом начале статьи:



    "Navigation.openMenu(menu)” содержит реализацию открытия меню с помощью библиотеки Masquerade.


    Библиотека впоследствии была расширена и появились универсальные шаги, которые могут быть использованы для любого CUBA-приложения. Это шаги, позволяющие работать с элементами программы: кнопками, полями, таблицами. Эти универсальные шаги и стали тем набором стандартных фраз, которые мы используем в BDD для написания сценариев.


    Благодаря связке Masquerade+Gauge мы существенно снизили трудоемкость создания тестов. Теперь тесты могут писать люди, не имеющие особых навыков программирования. Тест может писать один человек (раньше сценарий придумывал один, а реализовывал — другой, что приводило к путанице). Итак, мы добились своей цели — интерфейсы упрощены, а аналитикам не составит труда писать тестовые сценарии.


    Изменения процесса изображены ниже:


    Было:

    Было


    Стало:

    Стало


    В сравнении видно, что требования, спецификация и тест документация объединены в один пункт. Тест документация является и автотестом, за исключением имплементации специфичных тестовых шагов.


    Итоги


    На данный момент мы успешно ведем разработку по обозначенной выше схеме. И нам удалось избавиться от главной проблемы BDD — серьезного увеличения сроков из-за сложности реализации, добавив и доработав инструментарий. Однако, качество выдачи продуктов улучшилось.


    Временные затраты на поддержку документации сокращаются пропорционально количеству измененных спецификаций, т.к. одно изменение спецификации (логики системы) приводит автоматически к изменению автотеста за одну итерацию. Т.е. тестировщику не нужно лезть в систему документации (типа Confluence и т.д) для апдейта, и для других участников команды это тоже справедливо.


    Время на реализацию и поддержку тестов при наличии библиотеки, упрощающей работу с объектами страницы, уменьшилось в два раза, по сравнению с работой с обычным чистым web -driver и затратами на переделку ссылок XP.


    В разработке любого бизнес решения и в управлении качеством — стоимость устранения ошибок сбора требований и анализа растет экспоненциально. Соответственно вероятность получения проблем, связанных с переделкой продукта, согласно существующим статьям и графикам при итеративной разработке, при раннем обнаружении проблемы, которая заключается в хорошей проработке требований, существенно снижает стоимость разработки, в зависимости от проекта. Это может быть и 0% и ~ 40%. Именно это улучшение достигается за счет внедрения BDD. Это можно внедрить и не называя это словом BDD, но в BDD оно есть. Наличие возможности обойти проблемы является важной частью обеспечения качества.


    В завершение, хотелось бы отметить, что данная схема разработки также интегрирована у нас с Continuous Integration и разработанной в нашей компании системой тест менеджмента — QA Lens. В QA Lens можно писать те же сценарии, что и в IDEA, используя предметно-ориентированный язык. Этот язык состоит из ранее составленного глоссария доступных действий, которые ранее имплементированы. При выполнении автотеста на Gauge с машины разработчика или CI — в QA Lens автоматически отмечается: какие шаги сценариев были пройдены, а какие нет. Таким образом, прогнав автотест сценария, написанного аналитиком, отдел тестирования сразу получает полную актуальную информацию о состоянии продукта.


    Авторы: Сунагатов Ильдар и Юшкова Юлия (Yushkova)

    Haulmont
    73,44
    Создаем современные корпоративные системы
    Поделиться публикацией

    Похожие публикации

    Комментарии 22

      +1
      Давайте начнём дискуссию ) Я живу несколько в другом мире в контексте бдд. В нём не обязательно писать тесты на геркине, их можно писать и кодом. А суть в том, чтобы мыслить поведением, а не реализаций. На примере UI автоматизации логина реализацией будет
      loginPage.loginField.enterText('login');
      loginPage.passwordField.enterText('password');
      loginPage.loginButton.click();

      Проблема здесь в том, что, если процедура логина поменяется, то править нужно будет большое количество тестов. С этим нам и помагает бдд:
      loginService.login('login', 'password');
      Реализацией метода логин как раз и будет весь предыдущий код. Теперь изменения будут только в одном месте. Геркин тут не обязателен (а в моём мире ещё и нежелателен) ровно как и писать такие тесты до реализации кода, за что отвечает TDD подход. Миксовать их необязательно (но в моём мире желательно), т.к. они в принципе решают разные независимые друг от друга проблемы.
      PS Я не утверждаю, что автоар не прав, но буду рад подискутировать, ибо в споре рождается истина.
        0
        Получается вы рассматриваете BDD как упрощение написания кода, когда речь идет о том, чтобы писать тесты на понятном человеку, без опыта программирования, языке. Не каждый Бизнес Аналитик, сможет читать код и уж тем более писать на нем.
          +1
          Не каждый бизнес аналитик пишет тесты ) Это раз, два — у меня был проект на кукумбере. Я туда пришёл на синьёрную позицию и первые 3 месяца не мог самостоятельно писать тесты как раз из-за кукумбера (конечно, там было не самое лучшее решение и можно сделать лучше, но проблемы всё равно есть в плане написания не программистами). И три — я делал эксперимент: посадили мануальщика, сказали, что есть какое-то слово service и, если после него нажать точку, то будут подскази чего тут можно делать дальше. И парень сам написал тест без подсказок вообще. Так что вопрос спорный )
            +1
            Ну суть как раз в том, чтобы аналитик начал их писать :)
            И я не спорю, что научить можно кого угодно и чему угодно, весь вопрос в сроках и целесообразности.
              0
              Вы знаете аналитика без знаний программирования, который может сам писать тесты на кукумбере? А моём опыте это было чрезмерно сложно, как в написании, так и в поддержке.
                0
                С использованием Gauge, да.
                  0
                  Сильно похоже на кукумбер, но эту штуку я не юзал, так что говорить не буду.
                  0
                  Про кукумбер скажу — есть знакомые, кто пишет без знания движка под капотом. Есстественно всему нужно некоторое время подучиться, как в случае с примером о «service._»
                  По поводу сложности: действительно есть сложность в том случае, если аналитик не знает каким глоссарием оперировать. Если система разработки не подсказывает или не подсказывает утилита в которой есть список этих фраз, то шаги будут записаны в произвольной форме, и их нужно будет корректировать, но все же проще подкорректировать одну точку входа, чем синхронизировать тестовую документацию, описание требований и автотест.
                0
                Согласен с тем, что не каждый аналитик пишет тесты ) Для аналитика является хорошей практикой описывать юзер кейсы, т.е описывать как (и зачем) поведет себя пользователь и система, т.е. ожидаемый результат. И это является почти тем же самым что и описание сценария. Вопрос в том, ставилась ли задача работать по BDD, если да, то вся команда должна понимать, что мы делаем с требованиями, соответственно когда их записываем, кто отвечает за результат того что записали, а это результат всего взаимодействия заказчика и исполнителя.
                  0
                  Задача ставилась, но решение с кукумбером было на столько сложным к написанию, что задачи писать тесты не автоматизаторам не было. Написано было на английском не как код, да, но писать самому аналитику — вообще никак )
                    0
                    Предположу, что варианты шагов нужно упростить, либо переписать в таком виде, как будет удобно воспринимать большинству. Имплементаций остается, а именование меняется, ну либо создается чуть больше частных случаев.
                      0
                      То всё не так просто ) Не в последнюю очередь благодаря ограничениям, накладываемым кукумбером.
              0
              Gennadii_M спасибо за первый комментарий )
              Суть BDD как раз в том, что бы точка входа была одна, т.е. что бы требования соответствовали тому, как будет тестироваться. В вашем же случае возникат вопрос, документация требований, тестовая документация у вас ведется отдельно? И сами тесты никто не смотрит, кроме службы QA? Описанный Вами пример больше соответствует TDD, хотя упомянули то, что не пишете тест до разработки, получается TLD. Написание тестов на фреймворке jUnit с поведенческой точки зрения это логично, у нас тоже использовалось раньше и используется сейчас, но там нет связи с материалом, который поймет заказчик. Если взять частный случай, на примере нашей компании, то для обхода этой ситуации у нас есть решение. Для того что бы связать jUnit и читаемое любым человеком языком описание есть инструмент QA Lens, который мапит jUnit тесты на документацию.
              Скажите, пожалуйста, если не серет, почему нежелательно писать текстовое описание, который поймет не технический специалист? И какой фреймворк использовался?
                0
                Я пишу на тайпскрипте, тест раннер — jasmine. Мануальщики код тестов читают без проблем. Заказчик не читает тесты вообще. Ни в коде и в tms.
                Единая точка входа — это, конечно хорошо, но только тогда когда тест кейсы написанные мануальщиком автоматически становятся авто тестами. Если их всё равно надо переписывать в авто тесты, то смысл пропадает. А именно так и происходит в 100% случаев, про которые я слышал и видел сам.
                А сам кукмбер — это лишний слой абстракции, который накладывает значительные ограничания на архитектуру, которые надо как-то извращённо-костыльно решать.
                  0
                  BDD это дополнительный слой абстракции, тут согласен. С другой стороны это возможность написать автотест тестировщику, который пока никак не дружит с кодом.
                  По поводу костыелей при имплементации: это проблема. Контролы могут быть разные, технологи разные. Но мы как раз и упомянули в статье о проблемах реализации BDD, в некоторой степени нам помогла библиотека Masquerade, в некотрой степени изменение процесса.
                  Если стабильные степы (шаги) падают, то тут уже полет фантазии, если это связано с особенностью работы с новым функционалом, то возможно придется плодить несколько вариантов практически одного и того же, либо усложнять текущий.
              0
              имхо, это для команд, где нет програмистов, а только кодеры

              выглядит так, как будьто программист на человеческом языке получил шаги, что надо сделать, и только перевел это в код

              причем большая часть работы сделана уже до него
                +1
                Уточните, пожалуйста, кто подразумевается под кодером, а кто под программистом.
                  0
                  А есть же ещё разработчики и инженеры )
                +1
                Ильдар, спасибо за статью. Подскажите, как Вам удалось привлечь аналитиков к написанию сценариев в BDD?
                  +1
                  Изначально инициатива использования BDD шла от зарубежного заказчика, поэтому было немного проще. Сейчас мы пробуем использование на другом проекте, но тут уже есть интерес у наших аналитиков. Сложность заключается в том «как писать?», поэтому первая задача в данном случае правильно назвать шаги, что бы ими было удобно оперировать. Помимо этого очень большое значение дает понимание команды, в каких частях общей работы получится выгода. Если понимания нет, то и «заставить» никого не получится
                    0

                    Понятно, спасибо :)

                  +1
                  Мы сделали BDD на jBehave, так как Java команда могла помочь с быстрым стартом и написанием всех необходимых компонентов для используемых сценариев. Инициатива шла от нашей команды, т.к. при использовании BDD мы сильно экономили на тестировании при частых выпусках новых версий. Я бы не сказал, что BDD это дорого, нужно правильно разложить процесс и посчитать издежки и экономию. Новые компоненты нужны нечасто. В основном тестировщики справляются со сценариями без помощи разработчиков.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое