Адаптируем BDD для разработки на 1С совместно с cucumber и 1Script

Кто платит за тестирование решений? Особенно в случаях если заказчик (внутренний или внешний) просит запустить систему учета, и не указывает насколько плохая система ему нужна? Этот вопрос вызывает достаточно большую волну «священных войн» при любой разработке, любых решений. Написаны они на 1С или не на 1С — это извечная «драка»: никто не любит тестировать, все любят «кодить» новые и интересные задачи.Но чтобы, хотя бы попробовать сдвинутся с мертвой точки, необходимо разобраться в том, что тестирование как понятие относится к процессу разработки. Значит все же придется тестировать разработчикам. Но вот как это сделать максимально удобно?

BDD, DDD, TDD, PDD, SDD и остальные <всякие>DDРазмышляя над проблемой тестирования, а точнее над проблемой качества решений, умные и не очень люди, в основном ломают копья.над следующим противоречием

8c2328d23e684e23b0ca28943b238579.png

«надо тестировать, но надо разрабатывать, а не тестировать».

Также к этому добавляется другое противоречие

«надо предусмотреть все возможные действия будущего пользователя, но нельзя предусмотреть ВСЕ действия будущего пользователя»

9564b4952b574f598b2fa02c87367e0c.jpg

Всё становится еще хуже, когда к этому мы добавим еще огромное количество подходов к проектированию и разработке. Например, как это классифицирую я, когда мне необходимо объяснить сущность проблемы.

Domain DD — способ разработки, когда цель заказчика сформулирована в виде базовых сущностей будущей системы: «Хочу Товары, Инвентаризацию, Акты списаний и оприходований»

Report DD — способ разработки, когда цель заказчика формулируется в виде конечных отчетов с анализом данных: «Хочу отчет о прибылях и убытках»

User Interface DD — способ разработки, когда цель заказчика сформулирована в виде конечного пользовательского интерфейса: «Хочу вот такую формочку для сотрудника на проходной по выдаче пропусков»

Behavior DD — способ разработки, когда цель заказчика сформулирована в виде конечного процесса ожидаемого в системе, или даже группы взаимосвязанных процессов: «Когда мы фиксируем отправку машины из Москвы, тогда нужно чтобы изменился статус заказа и зафиксировалось время отправки, а также надо учесть косвенные затраты на перевозку в себестоимости заказа»

Отдельно стоит выделить еще 3 подхода, которые обычно нигде не описываются

Sabotage DD — способ разработки, когда цель заказчика формулируется в виде ускоренных сроков требущих разработки напрямую в Production системах: «Срочно добавьте на форму реквизит Булево =Ромашка=». Применяется при попытках заказчика построить управляемый хаос в команде разработки — используется в политических целях.

Moratorium DD — способ разработки, когда цель заказчика не в запуске функциональности, а в соблюдении регламентов и нормативов утвержденных на предприятии: «Любое изменение в системе должны быть согласовано с <ЛистСогласования>, любые работы по проектированию, разработке и прототипированию не могут быть проведены без указания проекта и его технико-экономического обоснования».

Pain DD — переходный способ разработки, когда цель заказчика повысить качество решений, не снижая сроков выхода функциональности: «Хочу чтобы вы производили всестороннее тестирование, но кстати не забудьте первого числа запуск системы WMS, не дай бог вам сорвать сроки. Да и кстати ФОТ нам в этом году урезали — выделенных тестировщиков не получите».

И это не «троллинг» Если кому-то показалось, что эти 3 последних подхода выделены и описаны в порядке «стёба», то сразу скажу — это не так: в определённых случаях такие подходы дают определённую долю эффективности, правда не ИТ департаменту. ИТ специалисты, здесь «чаще всего в проигрыше».

Классификация конечно топорная и очень уж приземленная, но для подготовки специалиста к чтению умных книг по этому поводу, достаточная.

Есть еще и FeatureDD (разработка, когда цель заказчика сформулирована в виде небольшой легковесной функциональности), и ModelDD (разработка, когда цель заказчика сформулирована в виде конечной таблицы с полями), но я их обычно не использую по следующим причинам:

в 1С мире чаще заказчик сразу формулирует ожидаемое поведение «behavior», а так как «поведение» всегда сложное, то feature«s возникают сами собой при декомпозиции/категоризации сценариев. в 1С мире все домены/модели всегда сложные (а точнее сложно-функциональные) и имеют более двух зависимых сущностей и более двух функциональных связей. А корректные model«s возникают сами собой уже в рамках декомпозиции сложных доменов — иначе не построить корректный граф зависимостей доменов. Советую всем приглядеться к v8.1c.ru/model/ — в системе как раз отражен DDD совмещенный с MDD, при небольшой адаптации ChangeManagementSystem. Вдруг кто не в курсе что это за аббревиатуры:

DD — Driven Development (разработка «через» или разработка «от цели») — один из способов организации процесса разработки в инженерии программного обеспечения. Входит в en.wikipedia.org/wiki/Software_development_process в виде отдельных методологий.

7c77600a22004caf97275843c8180802.gif

Окружение разработчика BDD для eDSL Те кто с eDSL миром знаком, а я так понял по предыдущей статье, их достаточно много на Хабре, скорее всего догадались куда я веду. Для тех кто не понял скажу: в 1С мире за счет того, что заказчик — не конечный бизнесмен, а любой пользователь предприятия: де-факто применим любой из подходов. Кто-то хочет отчет, кто-то поведение, кто-то вообще странного. Поэтому то в сообществе обычных 1С специалистов и используют формулировку xDrivenDevelopment — где x: любой подход, в зависимости от цели заказчика. Авторство принадлежит одному из участников сообщества и изначально звучало как yDrivenDeveloment, где y — некая целевая функция выполняемая разработчиком.

Но вернемся к тестированию. Итак, на входе у нас следующие данные:

Необходимо тестировать (а куда деваться) Необходимо разрабатывать (eDSL платформа для этого собственно и предназначена) Подход к процессу разработки может быть разный.(и ничего с этим не поделать) Все тесты не написать (ну или написать, но через лет 10 жизни системы) Требования к системе достаточно хаотичны, подходы к постановке требований также Мы хотим попробовать создать возможность разрабатывать через поведение на платформе 1С

Для работы нам понадобится:

а также концепт отражающий подход к тестированию 1С решение через поведение:

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

Дойдя до этого места, некоторые 1С специалисты сделают «широко открытые глаза» и возможно закроют статью. Для остальных продолжим, замечу следующий моменты:

я ожидаю, что при установке msgit вы сделали так, что он установился в $PATH не только сам, но и со всеми утилитами (настоящему 1С-нику необходимо привыкать к консольным утилитам из *nix мира — touch, mv, rm, grep и т.д.)

ruby нам понадобится чтобы установить «огурец«python — используется для работы с hook«ами git (дело в том, что для получения исходных файлов мы используем перехват помещения бинарных 1С файлов в репозиторий: ведь в репозитории исходных кодов все же должен быть исходный код).

Для тех, кто в данный момент испытывает боль от резкого перехода с теории к практическим работам, предлагаю смириться и продолжить чтение:

Первое что вы должны понять, тесты — это тоже код. А для кода мы просто обязаны сделать хранилище кода. Поэтому:

$ mkdir EnterpriseAccounting $ cd EnterpriseAccounting $ git init./ $ mkdir features $ mkdir tests $ mkdir src $ touch README.md теперь осталось только разобраться где хранить тесты на сервере git

$ git set origin https://dev.example.com/foobar/EnterpriseAccounting $ git push кто такой touch и что это за команды если вы правильно установили msgit, то тогда у вас эта команда уже присутствует, справку по ней можно посмотреть через touch --helpвсё остальное типовые команды при работе с исходными кодами:

создать локальную директорию инициализировать репозиторий внутри неё создать структуру каталогов сделать задел по будущей документации для команды указать центральный сервер отправить в центр (поделится с командой) Тестирование конечной задачи, это не тестирование алгоритма функции Перейдем непосредственно к задаче. Тут опять придется несколько отвлечься и сказать, что при запуске разработки автоматизированного тестирования 1С, основная проблема это как раз непонимание «как тестировать» конечный бизнес-функционал. Возможно здесь также играет «злую штуку» название известного проекта xUnit — которое отсылает нас к en.wikipedia.org/wiki/XUnit, где мы читаем много умных слов, но они слишком далеки от конечного тестирования бизнес-задачи.

И вот тут у начинающего разработчика, которому поставлена задача на автоматизированное тестирование, начинается «ломка стереотипов», дело в том что Конфигуратор 1С позволяет сразу реализовывать полученное ожидаемое поведение, без необходимости его обдумывать и задавать вопрос «зачем» и «кому» необходим функционал. Изначально считается что все заказчики-бизнесмены и специалисты по eDSL языку максимально находятся «в контексте». Для одного поведения это скорее всего так, а вот для комплекта ожидаемых поведений и сложных сценариев ни один мозг не сможет удержать в контексте весь сценарий задачи. Как раз за этим мы и начинаем относится к ожидаемому поведению как к коду.

Обычный типовой процесс для разработчика Задача от заказчика (в системе учета задач) звучит исходно так

«Необходимо что деньги учитывались как аванс, если клиент оплатил больше чем мы ему отгрузили»

Теперь посмотрим как это выглядит в реальности и прикинем что нам нужно для BDD в 1С:

Парсер для языка Gherkin, который будет выполнять две функции: помогать нам генерировать процедуры для тестов и, собственно, запускать потом готовые тесты и формировать отчет об их прохождении. Для этих целей мы будем использовать Cucumber (тот самый «огурец») Было бы хорошо, если бы был инструмент, который получая от Cucumber готовые имена тестов (вместе с параметрами) создавал нам готовые файлы обработок в формате внешней обработки 1С (мы же помним: всё что может быть автоматизированно — должно быть автоматизированно). Технически — это скрипт написанный на языке 1Script. Он позволяет связать Cucumber и 1C между собой посредством wire протокола cucumber, 1Script Socket, и OLE соединения с 1С.Т. е. на вход мы получаем feature файл — на выходе готовую обработку 1С, которую можно отдавать разработчику. И всё это за один клик. Те обработки, которые мы получим — это и есть наши тесты. Это код, а код надо хранить и версионировать. Для этого мы ставим Git. После того как разработчик наполнит эти тесты кодом, их надо будет разложить на исходники (а как же, мы же не будем хранить в репозитарии только бинарные файлы). Для этой цели мы возьмём Precommit1c от сообщества xDrivenDevelopment. Теперь, когда мы помещаем готовый файл в Git, он будет распарсен, разложен, декомпилирован, деклассирован (выбрать нужное). И само собой автоматически, за один клик, ну вы поняли. Дальше идет достаточно важный и очень обязательный шаг при «разработке через поведение» — мы пишем ожидаемый сценарий поведения (или аналитики за нас, или грамотный заказчик). Фактически Gherkin, а мы будем использовать именно его, спасёт нас здесь, тем, что мы имеем DSL язык для описания группы будущих тестовых сценариев. Наверное вы удивились что я сказал про будущие тесты? Но вы должны смирится — после использования BusinessReadableDSL для описания сценария происходит понимание что же действительно нужно протестировать, и что же действительно нужно реализовывать (ищете статью Мартина Фаулера на эту тему).

Итак, у нас есть feature файл, который мы напишем на основе исходной постановке задачи, следующего содержания:

$ touch ./feature/account_loan.feature $ notepad++ ./feature/account_loan.feature Функционал: Поступление оплаты по существующим договорам и зачёт аванса контрагента

Как Бухгалтер Я Хочу чтобы чтобы при фиксации оплаты от Контрагента происходило распределение поступившей суммы по договорам, на котором существует долг И происходила фиксация оплаты в виде аванса, если долг отсутствует

Контекст: Когда есть Конфигурация 'Бухгалтерия 3.0 (Такси)' И существует Контрагент 'тестовый Контрагент' И существует договор 'тестовый договор Контрагента 1' с датой договора 02.01.2014 И существует договор 'тестовый договор Контрагента 2' с датой договора 03.01.2014 И Введена учетная политика

Сценарий: Поступление суммы достаточной только для погашения существующего долга Допустим 'тестовый Контрагент' имеет 2 покупки по 2 'тестовым договорам' на сумму 1000 и 300 рублей Когда фиксируется оплата по 'тестовому Контрагенту' на сумму 1100 рублей Тогда формируется проводка по счету '62.01' по 'тестовый договор Контрагента 1' на сумму 1000 И формируется проводка по счету '62.01' по 'тестовый договор Контрагента 2' на сумму 100 И на счете '62.01' по 'тестовый договор Контрагента 2' остается долг в размере 200 рублей Как я создал такой feature файл Я просто ответил на типовой комплект вопросов из Gherkin, немного подробней опросив заказчика по следующему списку: Что за функционал Что за роль В чем цель Какие сценарии поведения мы ожидаем В каком контексте необходим данный функционал Запускаем vanessa-behavior.os с параметром «GenerateEpf» и получаем на выходе готовый файл обработки для тестирования:

$ oscript.exe vanessa-behavior.os --GenerateEpf --ProjectPath=»<Адрес репозитория с Feature файлами>» --1cConnectString=«File=<СтрокаСоединенияС1С>» и получаем то ради чего всё это затевалось — обработку тестирования на основе поведения, которую мы затем и наполняем при помощи кода на встроенном языке 1С

b84629c494f24aaa804d47b736a0176d.jpg

Как видно — произошло следующее:

Для каждой строки feature файла была создана процедура.

Например строка

Когда есть Конфигурация 'Бухгалтерия 3.0 (Такси)'

превратилась в

Процедура ЕстьКонфигурация (Парам01Строка) Экспорт

Были определены параметры для вызова этих процедур (число, строка, дата), а также были определены, так называемые сниппеты, например:

//»@СуществуетДоговорСДатойДоговора (Парам01Строка, Парам02Дата)» Давайте посмотрим, что с этим добром можно делать.Первое, что бросается в глаза, что имя параметра Парам01Строка не очень наглядный. Что же, берём и меняем ему имя, скажем, на НазваниеКонфигурации. Да и имя процедуры заменим на СуществуетКонфигурация.Получится:

Процедура СуществуетКонфигурация (НазваниеКонфигурации) Экспорт Но тут может получиться ситуация, что если попытаться ещё раз сгенерировать обработку 1С по тому же feature файлу, то программа не сможет найти процедуру со старым именем и всё перестанет работать. Но тут нам на помощь приходит сниппет

//@СуществуетКонтрагент (Парам01Строка) по которому мы всегда сможем определить какой именно метод вызывать (правда для этого нам придётся распарсить исходники обработки, и построить таблицу сниппетов и реальных имен процедур, но нас такие мелочи не пугают).

Второе, что можно заметить, это то что в feature файле были две похожие строки:

И существует договор 'тестовый договор Контрагента 1' с датой договора 02.01.2014 И существует договор 'тестовый договор Контрагента 2' с датой договора 03.01.2014 Но для них был создан только один метод:

Процедура СуществуетДоговорСДатойДоговора (Парам01Строка, Парам02Дата) Экспорт Что не удивительно, ведь для обеих строк сниппет будет одинаковый. Таким образом может показаться, что тут назревает повторное использование кода. Иииииииии… Да! Это оно и есть! Если где-нибудь в этом feature файле (или в любом другом этого же проекта) мы напишем что-то вроде:

И существует договор 'Какой-то там договор' с датой договора «какая-то дата» то окажется, что этот код тестирования уже реализован в методе СуществуетДоговорСДатойДоговора.

Мало того, может оказаться, что этот метод реализовал вообще кто-то другой до нас. И мы просто его переиспользуем. И это произойдёт само собой. Это ли не мечта любого программиста! Заказчик пишет что он хочет (а это и есть наш feature файл) —, а половина кода уже реализована, протестирована (т.е. покрыта тестом) и будет подхвачена на лету! Welcome to the BDD, my friend!

d00109663cda400b9cf2d0485094c8ac.jpg

Подведём мини итог.

У нас есть то, что хочет заказчик: это описано на декларативном языке Gherkin. Запускаем генератор — получаем готовые файлы тестов, которые надо будет наполнять кодом. Пишем тесты (или генерируем через новый функционал записи действий пользователя), одновременно пишем/конфигурируем тот функционал, который хочет получить заказчик. Запускаем vanessa-behavior.os — и идет выполнение наших тестов, используя всё ту же feature от заказчика. Получаем отчет о прохождении тестов в json или, например, в html (не забудем про проект Allure) В рамках одной статьи трудно охватить такую большую тему как BDD и как это адаптировать в мир 1С. Надеюсь, будет отдельная статья целиком посвященная этой тематике, но с уже более подробными примерами.

Инвентаризация функционала и технический долг Обычно, те кто изучают данный материал, как я и говорил в первой статье, отказываются начинать писать через тесты.

Происходит это по двум причинам:

после введения правила «Любую задачу мы берем в работу только после понимания того как её будем тестировать», основные затраты по времени начинают тратится на наращивание тестов на первичные и мастер данные — таки как контрагенты, номенклатура, учетная политика и т.д. Одновременно с этим приходится генерировать тестовые данные, так как всем становится понятно, что база для автоматизированного тестирования должна быть чистая. Не все готовы это делать — так как приходится ретроспективно взглянуть на всё что «мы накодили» до момента X (переход на BDD). Решается такая проблема так называемым методом «технического спринта» — как его согласовать с заказчиком (или не согласовывать) — это отдельная песня родом из Agile. трудно… всё-таки BDD|xDD родом из инженерных практик, поэтому требует высокий уровень ответственности разработчиков в команде. Всегда трудно становится ответственным, когда до этого 6 лет был безответственным. Решается такая проблема двумя способами — так называемой методикой social presure и введение практики release managment«а. То есть когда «без тестов писать фу-фу-фу» и когда релиз без тестов к production не допускается инженерами ответственными за рабочую систему. Если вы один и «многорукий Шива» — то только внутренний ИТ перфекционизм вас и спасёт. В общем случае переход на «разработку через ожидаемое поведение» временно увеличивает затраты команды. На текущий момент у нас следующие цифры — увеличение скорости разработки и уменьшение количества ошибок (улучшение качества) начинается где-то через 1 месяц, для команды из 5 человек уровня обычных программистов 1С. Поэтому в течении 1 месяца вся команда должна жить в перманентном стрессе и смириться ;-). Хотя опять же для менеджеров мы вынуждены заметить, что можно и не прерывать разработку по старому, запустив отдельно фазу сбора требований в виде feature файлов, а уже потом запускать фазу тестирования (хотя это и противоречить самой концепции, для переходного периода это допустимо). Немного истории, для совсем не сведующих Отдельно стоит сказать, как это все начиналось и как развивалось, По моей версии это было так (хотя старшие товарищи могут меня поправить).Начиналась проверка концепции xDD (а точнее с TDD), еще в далеком 2004 году и на платформе 1С 7.7. Принято считать, что лидерами здесь являются Московская школа по тестированию — в том числе в рамках проекта www.1cpp.ru и Ижевская школа по тестированию www.kint.ru

С выходом версии 1C 8.* никто и не собирался отказываться от уже наработанных процессов, однако закрытость платформы привела к невозможности прямым способом портировать наработки. Процесс немного остановился.

Но тут всех спас Яндекс и руководитель отдела тестирования;-) (Да-да — в Яндексе тоже была или еще есть 1С).

В итоге появились первые draft«ы infostart.ru/public/15492/ очень даже работоспособные, и уже при объединение нескольких наработок и родился проект github.com/xDrivenDevelopment/xUnitFor1C, для развивающих качество своих решений разработчиков на платформе 1С. Лидером в данном продукте является Артур Аюханов с командой единомышленников.

Но нельзя не вспоминать об Ижевской школе тестирования 1С решений. На данный момент основным фронтменом здесь является Ижевское тестирование систем — команда здесь построила схему монетизации тестирования и развивает уже свою линейку коммерческих продуктов.

Проект vanessa-behavior является продолжением развития концепции xDD, но уже с другим подходом — теперь не от тестов, а от требования к поведению.

FAQ

Q: Я пробовал, у меня не получилось. Как вообще это использовать ?.A: Проект работает на последней (develop) версии 1Script и ждет выпуска релиза 1.0.9, а также будет планомерно дорабатываться под текущие задачи. Поэтому не волнуйтесь — всё будет.

Q: Что почитать на эту тему ? A: Материалов достаточно много, но:

Q: Зачем здесь GherkinA: DSL язык Gherkin для описания требований — это прямая отсылка вас к проблеме управления требованиями и как она решается автоматизировано.

Q: Зачем тестировать типовой функционал типового решения 1С ? A: Как я неоднократно заявлял, автоматизированное тестирование это «игра в длинную». Наличие ожидаемого поведение от внедряемой системы поможет упростить обновление на новую версию типовой конфигурации 1С, а также вести свою разработку на основе типовой конфигурации. Правда эта проблема уже из другой «оперы» (для знающих английский). Вместе с этим я категорически рекомендую подсматривать в «кулуары», где уже наличествует возможность расширения, которое придется разрабатывать с учетом уже ваших тестов.

Q: А когда будет публикация про xUnitFor1C? A: после долгого обсуждения мы посчитали, что публикацию про xUnit делать стоит группе авторов из организации xDrivenDevelopment, от себя же мы можем поделиться только начальным восьмичасовым видеокурсом и публикацией на Инфостарт, публикацию по xUnitFor1C все же должен делать лидер это продукта

Q: Какая следующая публикация ? A: Это все же будет Docker для 1С, после официального релиза docker-compose и docker-machine, а также развития docker до 1.5 теперь это действительно будет полезно уважаемому ХабраСообществу.

© Habrahabr.ru