Меня зовут Виктор Мясников, я отвечаю за качество продукта в «Юле». Я закончил Бауманку и хотел строить ракеты, но с ними не вышло, поэтому теперь профессионально строю «велосипеды» для QA, а ещё люблю уничтожать рутину. Я расскажу, как мы проектировали BDD-фреймворк и зачем он вообще нам понадобился. «Юла» — это сервис объявлений, представленный в iOS, Android, ВКонтакте и вебе. Когда мы делали BDD-фреймворк, у нас была отдельная QA-команда, которая тестировала API. Чтобы вы представляли ситуацию, я познакомлю вас с одним из тестировщиков этой команды. Все имена вымышлены, а совпадения случайны, но это поможет вам понять особенности, а где-то, быть может, увидеть совпадения с вашей ситуацией. Давайте познакомимся с Андреем — ручным тестировщиком. Сразу оговорюсь, Андрей – собирательный образ ручного тестировщика, история которого может показаться вам знакомой. Он уже более двух лет профессионально тестирует API. Андрей знает множество техник тест-проектирования и использует их в ежедневной работе. Естественно, он пробовал автоматизацию. Кто же из нас хотя бы раз не пытался её попробовать, когда только начинал? Изначально Андрей очень хотел автоматизировать, но, к сожалению, что-то пошло не так. Поэтому Андрей сделал вывод: «Автоматизация не нужна и всё только усложняет. Надёжнее тестировать самому». Каждый день наш Андрей приходит  на работу и тестирует задачи. Конечно, во всех командах и компаниях путь решения задач разный, но любая задача проходит основные этапы, например, тест на ветке и тест на релиз-кандидате. Как это выглядит? Андрей берет Postman и кликает, и кликает, и кликает, и … Вы поняли общую идею.Затем на следующем этапе он опять кликает, кликает, кликает, и так проходит его рабочий день. Так как автоматизация изначально не получилась, это и есть рутина, которая накапливается и увеличивается. Андрей не может «переварить больше», при этом он продолжает так делать каждый день. Казалось бы, ну и ладно. Но при таком подходе придётся столкнуться с несколькими проблемами. У каждого человека в нашей команде тестирования API была своя Postman-коллекция. Тестировщикам надо было как-то обмениваться ими: кто-то ушёл в отпуск, кто-то протестировал чужой релиз и надо об этом сообщить другому человеку. В итоге всё общение в команде сводится к фразе: «Дай последнюю коллекцию». Да, у Postman есть своё облачное хранилище. Оно упрощает обмен, но использовать его мы не могли: это небезопасно, а сейчас и вовсе может быть отключено. И действительно, всё так и работало: коллекции пересылали друг другу в Slack, Telegram или другом мессенджере. Их накапливалось огромное количество — номера версий переваливали далеко за сотню. Что же происходит в Jira при таком подходе? Происходит примерно следующее. Отчет о тестировании выглядит вот так: В Jira — бардак, и непонятно, какую полезную информацию команда может из этого получить. Наверное, такие комментарии хоть раз оставлял каждый QA. И больше скажу, я так же делал, когда начинал. Эти отчёты — действительно проблема, потому что никто не может воспроизвести, кто и что делал. Что же произошло с нашим Андреем? Плохое обучение автоматизации его демотивировало. Кликать ему надоело, и он расстроился. Сидел и думал: «Автоматизация не получилась, мне она не нужна. И что теперь делать?». С этим барьером сталкиваются многие: автоматизация однажды «не зашла», а рутины уже слишком много. Изначально, когда мы проектировали BDD-фреймворк, ставили задачу не испугать нашего Андрея. Он больше не должен был бояться автоматизации. Это было самое важное. Второе: не надо учить его программировать. Иначе опять натолкнёмся на барьер: у Андрея уже когда-то не получилось. И третий фактор: не изобретать велосипедов. Я, правда, их очень люблю, но в этот раз обошлись без них. Поскольку команда у нас уже была, мы выбирали технологии и делали фреймворк под неё. Посмотрев на опыт разных компаний, решили использовать подход BDD, а в качестве реализации взяли Cucumber. А поскольку я и команда автоматизации уже знали Java, то вопрос выбора инструментов отпал сам собой. Проектирование будущего взаимодействия начали с метода GET, как и изучение методов HTTP-запроса. Андрей сказал: «Мне ничего не понятно, но давайте пробовать». Ему стало интересно, что же такое мы можем ему предложить. Да и усталость от ручного кликанья накопилась. За основу мы взяли уже используемый командой Postman. Основное, что нужно было описать: Тип запроса — у нас это GET. Адресная строка. Тут всё просто, указываем её в кавычках.  Заголовки. Это пары ключ-значение, удобно использовать табличный вид: add headers |key|value|. Кнопка «отправить». Проверка статус-кода ответа: status code 200. Для зануд, любителей придраться к мелочам, или просто подробнее почитать про BDD подход можно начать с неплохой статьи тут, или поискать что-то самому, начав, как полагается, с вики.  В результате мы научились на языке Gherkin описывать действия, которые QA делал в Postman. Получили описание поведения системы, которое мы ожидаем.  Естественно, одним GET сыт не будешь, поэтому следующий запрос у нас POST.  Чем POST отличается от GET? У него есть тело, с которым есть проблемы:  Оно может быть сколько угодно большим по размеру, поэтому просто так вписывать его в тест не очень-то хотелось, иначе тот будет нечитабельный. Мы решили класть тело в JSON-файл, который лежит в определённом месте в проекте и будет отсылаться вместе с запросом. Для упрощения мы указываем только его имя.  В файле могут находиться какие-то динамические элементы, например, ID. Конечно его можно оставить в проекте в таком виде, но будет неудобно работать. Поэтому мы представили JSON-файл в виде так называемого шаблона. Это значит, что в момент выполнения во все динамические поля подставляются актуальные значения. А при проектировании теста они будут храниться в виде ссылки. Таким образом, перед тестом мы можем сказать, что у нас есть ID, который в момент выполнения заменится на актуальное значение. Естественно, наши тесты должны выполняться  в несколько потоков, поэтому мы сделали потокобезопасное хранилище таких переменных, где выполняются всего две операции: put и get. С помощью такой нехитрой манипуляции мы можем делать динамические элементы в наших JSON-файлах. У нас уже есть проверка статус-кода наших запросов, но это не совсем честная проверка, ведь нам интересно проверять сами данные. Поэтому мы взяли язык запросов в JSONPath, который позволяет находить элементы в структуре JSON-документа. У нас есть сам документ, и по $ мы можем попасть в его корень, выполнить запрос $.id и получить тот элемент, который нам нужен, то есть ID конкретно в этом JSON-файле. А значит, мы можем сделать проверку, которую несложно реализовать. Подробнее почитать про JSONPath можно в одном из первоисточников тут. Такая реализация позволила Андрею написать первый набор автотестов. Этого достаточно, чтобы начать покрывать наше API, но этим дело не ограничилось — у нас же несколько стендов. Как ребята («Андрей») поступали в Postman со стендами? Они заводили себе несколько окружений, например, dev, release, и туда через переменные подставляли нужные данные. Если гуглить по фразе «как сделать мультистендовость», вы практически везде будете находить одно и то же решение: заведите два файла dev.properties и release. properties. Мы тоже так сделали, потому что это простое решение. Но когда отдали файлы Андрею и команде, то заметили, что в них начали появляться вот такие записи: Оказалось, что набор цифр — это секреты конкретного стенда. Периодически они менялись, нам приходилось идти в репозиторий, находить файлы и менять секреты. У других QA в старых ветках это всё утрачивало актуальность, им приходилось постоянно актуализировать рабочие ветки, что усложняло работу. И чем больше таких секретов становилось, тем сложнее было это поддерживать. Были, конечно, экзотические варианты решения — менять property-файлы «на лету», но мы нашли более изящное решение — Vault. Vault — это защищенный сервис, хранилище типа ключ-значение. В нём мы завели столько папок, сколько было стендов (в примере выше — dev и release), и занесли туда ключи, хосты и так далее подробнее почитать про Vault можно тут и тут ). Это позволило вывести секреты из проекта, и теперь менять их можно без нашего участия. Это важно потому, что секрет может менять, например, команда эксплуатации в целях безопасности. И теперь эта команда знает, где лежат секреты у нас и у них. Подчеркну — это безопасно. Секреты не хранятся в проекте, в репозитории их нет. Таким образом, мы нигде их не раскрываем и нам больше не нужно их поддерживать вручную.  Предложенная реализация понравилось Андрею и его команде: работать стало проще, и ребята стали приходить за новыми возможностями.  Первый запрос поступил от другого члена команды: дать возможность считать хеши. Раньше он делал это онлайн MD5-генератором, что было, во-первых, не совсем безопасно, а во-вторых, не очень удобно. Этот запрос был простым в решении.  Второй запрос: нужны новые UUID. Оказывается, у ребят была открыта вкладка UUID-генератора в Chrome, и каждый раз они генерировали их вручную. С этим тоже может справиться BDD-фреймворк. А вот третий запрос заставил задуматься. Меня попросили посчитать сумму в проекте. Возник вопрос: «Хочется ли нам поддерживать всю арифметику самостоятельно?» Ведь если нужна сумма, значит скоро появится разность, умножение, деление и вообще вся базовая арифметика. А это трудоёмкая задача. Я обещал, что обойдёмся без велосипедов, поэтому начал искать решение, которое закроет все хотелки сразу. Что мы нашли? Скриптовый движок JEXL, который предоставляет готовую арифметику и возможность пробросить любую функцию на Java (подробнее почитать про JEXL можно тут). Интеграция очень простая: мы добавили его в наш pom-файл, объединили контексты и вызываем движок JEXL там, где нам надо. Как я уже писал, наш контекст реализует две базовые функции: get и put. JEXL работает похожим образом, у него есть два метода: get и set. Мы наш контекст объединили с JEXL-контекстом. Таким образом, теперь наши изначальные переменные — это переменные JEXL, и тесты умеют делать вот что: Мы можем написать функцию генерирования UUID, отдать её в тест, и человек просто её вызовет. Аналогичным образом заработала арифметика: теперь наши тесты могут выполнять все четыре операции без нашего участия. Правда, Андрей сказал, что это очень сложно. И это действительно было так. Пришлось потрудиться и объяснить, а потом написать несколько статей в Confluence, как это работает. Но по прошествии буквально нескольких дней тесты стали обрастать такими проверками и всё поехало куда быстрее. Андрею стало легче работать. Он преодолел барьер и почувствовал, что может автоматизировать тесты, которые будут ему реально помогать. За первые три месяца мы получили вот такой прирост автотестов у команды: За три месяца количество автотестов выросло вчетверо без ущерба для команды, релиза и практически с бесплатным ретестом. Внимательные читатели вспомнят про коллекции. Ребята, наконец, удалили их и в качестве источника правды начали использовать тесты. Хотите посмотреть, как реально работает бэкенд? Проще всего это сделать в тестах. Бонусом мы получили понятную отчётность. Естественно, подключили Allure, и теперь вместо комментариев — катим и протестировано — у нас есть ссылка на отчёт. Переходя по ней, каждый в команде может посмотреть что именно там происходит.  Вот так мы получили основу нашего фреймворка и команду, которая может автоматизировать без знания кода и без ущерба для себя и других.