Bdd тестирование 1с это
Copy raw contents
Copy raw contents
Зачем тестировать приложение
У каждого программиста (неважно, профессионал он или любитель) бывают случаи, когда его приложение ломается. Очень здорово, когда проблема ему хорошо знакома и решить её можно достаточно быстро, но иногда даже маленькое, незаметное изменение в коде может привести к часам, а иногда и дням безудерджного дебага.
В такие моменты хочется знать, какие части приложения точно работают, а какие нет. Существует множество путей решения этой проблемы.
Например, системы контроля версий (такие, как Git) позволяют просмотреть лишь те изменения, которые были внесены после выхода в свет последней рабочей версии приложения. Это позвояет не проверять всё приложение целиком и искать ошибку среди последних изменений.
Если же система котроля версия не используется или изменений после последней рабочей версии было слишком много, то найти ошибку всё ещё затруднительно.
На помощь приходит тестирование.
Качественное тестирование очень важно для приложения. Хороший тестировщик продумывает все возможные и невозможные исходы и проверяет каждый из них. Без такого тестирования невозможно гарантировать корректность работы прилолжения, а значит оно может сломаться в любом месте и в любой момент.
В идеале это работает так, что некоторый готовый блок кода проверяется тестами и в случае успешного прохождения он больше не трогается. На практике же часто приходится затрагивать один и тот же код, при этом именно тесты могут показать, что ничего не сломалось после внесения изменений.
Чем больше становится приложение и команда, которая над ним работает, тем больше вероятность возникновения ошибок и сложность их исправления. Тесты помогут избежать попадения этих ошибок в production, а также локализовать эти ошибки, что явно поможет их устранить.
Ещё одно применение тестов: описание требований к приложению. Заказчик описывает, чего он ожидает от некоторой функциональности, программист запускает тесты ( тестировщик тестирует готовый продукт) и таким образом показывает, что все требования заказчика были соблюдены.
Тестирование и его разновидности
Обеспечение качества (Quality assurance, QA) — способ предотвращения ошибок и дефектов в производимых продуктах, а также предотвращения проблем при доставке продуктов или услуг клиенту.
Тестируемая система (System under test, SUT) — система, которая тестируется на корректность работы.
Ручное и автоматизированное тестирование
Ручное тестирование — прямое взаимодействие QA-инженера с приложением.
QA ищет неисправности и недостатки, а затем информирует о них программиста.
Плюсы ручного тестирования
- Отчёт тестировщика — первый отзыв потенциального пользователя, позволяющий увидеть приложение его глазами.
- Обратная связь (feedback) по UI. Протестировать UI приложения и выявить его недостатки пока позволяет только ручное тестирование.
- Отсутствие затрат на написание тестов. Это важно при быстром внедрении новой функциональности. На малых проектах написание и поддержку тестов может оказаться достаточно затратным.
Минусы ручного тестирования
- Человеческий фактор. Часть ошибок может упускаться, некоторые результаты субъективны.
- Трудозатраты и продолжительность. Ручное тестирование обычно занимает много времени. Часто требуется тесное взаимодействие QA с программистом во время тестирования для разъяснения многих вопросов.
- Отсутствие возможности моделирования большой нагрузки. При ручном тестировании невозможно смоделировать большое количество пользователей.
Автоматизированное тестирование — написание кода для тестов.
Ожидаемый сценарий описывается кодом, затем при запуске тестов он сравнивается с реальным и программа указывает расхождения.
Плюсы автоматизированного тестирования
- Отсутствие человеческого фактора. Хорошо написанный тест не может забыть что-то проверить, он каждый раз последовательно проверяет действия.
- Скорость выполнения. Код для сценария пишется один раз, а его запуск обычно занимает несколько секунд.
- Переиспользуемость. Код автотестов может быть использован неоднократно, особенно при внедрении новой функциональности.
- Возможность моделирования большой нагрузки. Приближает тесты к реальной ситуации использования приложения.
Минусы автоматизированного тестирования
- Отсутствие тестирования глазами пользователя (UX). Не всё можно покрыть автотестами.
- Отсутствие обратной связи. Автоматизированные тесты не предоставляют обратную связь о качестве продукта, они лишь выполняют запрограммированные сценарии.
- Затраты на написание тестов и их поддержку. Автоматизированные тесты трубуют написания большого количества кода. При изменении тестируемых частей приложения, нужно изменять и их тесты (иначе они станут бесполезными). Это может быть губительно для маленьких проектов и проектов, где всё меняется довольно быстро и непредсказуемо.
Майк Кон, автор книги "Scrum. Гибкая разработка ПО", представляет тестирование приложения в виде пирамиды.
Чем выше по пирамиде, тем дольше и затратнее делать тесты.
По этой причине автор расставил следующие приоритеты: 80% — модульные тесты, 15% — интеграционные и API-тесты, 5% — UI-тесты (могут быть как автоматизированными, так и ручными).
Подходы к написанию тестов
Test-Driven Development (TDD) — разработка через тестирование; подход к разработке и тестированию, при котором сначала создаются тесты, которым должен удовлетворять код, затем его реализация.
TDD имеет итеративный процесс. Сперва пишется тест на новый, ещё не реализованный функционал, а затем пишется минимальное количество кода (ничего лишнего) для его реализации. При успешном прохождении теста, можно задуматься о качестве кода и сделать его рефакторинг.
- Полное покрытие кода тестами.
- Заранее задумываемся об использовании кода.
- Хорошие тесты являются неплохим примером использования кода (что-то вроде документации).
Например, напишем тест для функции, которая должна возводить двойку в степень.
Теперь на основании теста пишется сама функция.
Функция удовлетворяет тестам выше, добавим новые тесты.
Дописываем нужный функционал.
Далее снова пишем тесты.
Приемочное тестирование (Acceptance Testing) — тестирование, направленное на проверку соответствия системы требованиям.
Acceptance TDD (ATDD) - разработчка через приёмочные тесты. Подход близок к TDD, но отличается тем, что привлекает тестировщиков, программистов и сторону заказчика к совместному написанию критериев принятия тестов до начала написания кода.
Сперва придумываются критерий выполненной работы и критерий того, что она выполнена правильно. Эти критерии описываются доступным для понимания нетехническому человеку языком.
ATDD вносит ястность, что все участники проекта точно понимают, что необходимо сделать и реализовать.
Behavior-Driven Development (BDD) — разработка, основанная на поведении; расширение подхода TDD, где особое внимание уделяется поведению системы в терминах бизнеса. Такие тесты обычно иллюстрируют и тестируют сценарии, интересные заказчику системы. Поэтому для BDD-тестов используются фреймворки (Chai, Mocha, Jest) с синтаксисом, понятным не только программисту, но и представителю заказчика. Обычно этот синтаксис похож на английский язык.
Сравнение TDD, ATDD и BDD
TDD-тесты пишутся программистами для программистов. Они не указывают, что конкретно нужно тестировать и как именно должны выглядеть и называться тесты.
BDD вдохновлено архитектурой DDD (Domain-Driven Design) и фокусируется на предметной области приложения, в то время как TDD фокусируется на сам код, реализацию.
ATDD фокусируется на отображении требований в приёмочных тестах и использует эти тесты для разработки. Вопрос, определяющий ATDD-тесты: "Система делает то, что от неё требуется?".
BDD ориентирован на клиента (customer-focused), в то время как ATDD больше ориентирован на разработчика (developer-focused) и часто использует те же технологии, что и TDD.
BDD-тесты могут быть написаны и поняты не только программистом, но и техническими менеджерами или тестировщиками, что позволяет убрать языковой барьер между всеми ними.
Data-Driven Testing (DDT) — тестирование, управляемое данными; подход к архитектуре автоматизированных тестов, при котором тестовые данные хранятся отдельно от тестов (в файле или базе данных).
- Часть тестовых данных извлекается из хранилища.
- Выполняется скрипт, в котором вызывается обычный тест с извлечёнными тестовыми данными.
- Сравниваются полученные (actual) результаты с ожидаемыми (expected).
- Алгоритм повторяется со следующим набором входных данных.
Перепишем функцию pow2 из раздела TDD.
Возводить двойку в степень можно до бесконечности (на самом деле не совсем, поскольку в JavaScript MAX_SAFE_INTEGER = 2^53 - 1 ), но писать все эти степени руками не хочется.
Что можно сделать?
Можно взять файл, содержащий степени двоек и подгружать данные из его.
Пишем функционал, загружающий данные из файла и возвращающий их в виде массива.
Пишем функционал для тестов таким образом, чтобы можно было запускать их с массивом данных.
Считываем данные из файла и запустить тесты.
Загружаем данные из другого файла или же из другого источника, снова запускаем тесты.
Keyword-Driven Testing (KDT) — тестирование, управляемое ключевыми словами; подход, использующий ключевые слова, описывающие набор действий, необходимых для выполнения определённого шага тестового сценария.
Для использования подхода нужно определить набор ключевых слов и сопоставить им действия (функции).
В KDT используется что-то вроде таблиц, чтобы ключевые слова могли иметь параметры, поэтому подход иногда называют Table-Driven Testing (TDT).
- Считываем ключевые слова вместе с их параметрами из таблицы.
- Последовательно вызываем связанные с ключевыми словами функции.
Определяем ключевые слова: Login , Send Email , Logout .
Сопоставим им функции.
Теперь можно описать тестовый сценарий, например, следующим файлом (одна строка - одно ключевое слово).
Обработаем этот файл.
Чтобы выполнять действие в зависимости от ключевого слова, можно использовать простую функцию с конструкцией switch .
Осталось только считать строки из файла и выполнить то, что описано в каждой.
Тут можно сделать вспомогательную функцию.
Теперь можно выполнять любые последовательности, состоящие из определённых нами ключевых слов.
Для достижения изолированности какого-то блока тестируемого кода внешние зависимости при его тестировании заменяются тестовыми объектами.
Пустышка (Dummy) — простейший тестовый объект, реализующий интерфейс, минимально совместимый с интерфейсом реального объекта.
Код Dummy не содержит никакой логики.
Dummy используется в тех случаях, когда обращение к реальному объекту в данном тесте не имеет значения или отсутствует.
Например, нам в контексте теста не нужна проверка авторизации, поэтому мы заменяем реальную функцию checkAuth() на тестовую, которая всегда возвращает истиное значение.
В реальности же функция checkAuth могла иметь следующий интерфейс (token: string) => boolean .
Заглушка (Stub) — тестовый объект, частично реализующий логику реального объекта (валидные данные на входе - валидные данные на выходе).
Stub обычно содержит тривиальную логику, имитирующую работу нескольких методов реального объекта.
Например, имитируем создание пользователя в базе данных: принимаем данные пользователя и сразу же возвращаем полученные данные вместе с сгенерированным id (должен был сгенерироваться в бд).
Перепишем пример для Dummy так, чтобы он смог стать Stub (принимает валидные данные и отдаёт тоже).
Макет (Mockup) — модуль или класс, представляющий собой конкретную фиктивную (dummy) реализацию определенного интерфейса.
Макет, как правило, предназначен для подмены оригинального объекта системы исключительно для тестирования взаимодействия и изолированности тестируемого компонента.
Методы макета чаще всего из себя представляют заглушки.
Пусть имеется интерфейс, описывающий методы работы с базой данных.
Вместо того, чтобы использовать реальную базу данных, мы заменяем её фиктивной реализацией: реализуем интерфейс при помощи заглушек.
Объект-страница (Page Object Model, POM) — модуль (класс), представляющий интерфейс отдельной страницы тестируемой системы.
При использовании POM тесты оперируют с абстрактными объектами страниц и не завязаны на конкретную реализацию пользовательского интерфейса (его дизайн и вёрстку).
Тесты используют методы POM каждый раз, когда требуется взаимодействие с UI страницы.
Преимущества Page Object
- Изменение дизайна и вёрстки страниц может потребовать изменения только во внутренней реализации объекта страницы, но оно не затрагивает тестовые сценарии, оперирующие данной страницей.
- Абстрактность интерфейса позволяет переиспользовать тесты для различных девайсов. различных устройств и разрешений экранов, что очень удобно.
Шпион (Spy) — объект-обёртка (по типу прокси), слушающий вызовы и сохраняющий информацию об этих вызовах (аргументы, количество вызовов, контекст) оригинального объекта системы.
Сохраненные шпионом данные используются в тестах.
Испытательная Платформа (TestBed) — это специально воссозданная тестовая среда, платформа для тестирования (например, комплекс Макетов, Заглушек и Шпионов).
Испытательная Платформа применяется для комплексного тестирования отдельных связок системы или её компонентов.
Фикстура (Fixture) — механизм, позволяющий привести объект или всю систему в определенное состояние и зафиксировать это состояние для тестов.
Под фикстурой чаще всего понимают тестовые данные необходимые для корректного запуска тестов, а также механизмы загрузки/выгрузки этих данных в хранилище.
Основное назначение фикстуры: привести данные системы к определенному (фиксированному) состоянию, которое будет точно известно во время выполнения тестов.
Прямая связь кода с требованиями с помощью Gherkin
Код Gherkin(Дано, Когда, Тогда, И)
Код 1С (имена вызываемых процедур)
Дано: Контрагент (покупатель) «Иванов А.В.» оплачивает сумму 1000 рублей. Долг контрагента 500 рублей.
Когда: Фиксируется оплата от контрагента «Иванов А.В.» по договору «Основной» на сумму 1000 рублей
Тогда: Формируется проводка по счету «ВзаиморасчетыСКонтрагентами» на сумму 500 рублей (погашение долга)
И: Формируется проводка по счету «АвансыПолученные» на сумму 500 рублей (фиксируется аванс).
Каждой строке кода на языке Gherkin сопоставляется одна процедура на языке 1С. Сразу должны возникнуть вопросы. Почему только одна процедура и зачем вообще, что то связывать?
Что бы ответить на этот вопрос, давайте вернемся к первому пункту таблицы сравнения BDD и TDD.
Написание кода тестов до написания кода программы в BDD.
Как я уже упоминал, концепция написания кода тестов до написания кода программы в ВDD, реализована немного иначе, чем в TDD. В Test Driven Development, для нас важно только проверить логику программного кода, а в Вehavior Driven Development важно проверить конечные процессы в системе (хотя параллельно проверять логику кода никто не мешает). Данные процессы, как уже известно, описываются с помощью Gherkin. В технике BDD это неотъемлемая часть написания теста, а так же формулирования требований, написания документации и тд.
Но тесты на языке Gherkin невозможно выполнить, это не язык программирования. Но зато их можно связать с кодом на языке программирования. Важно чтобы эта была реальная связь, то есть код на Gherkin должен полностью соответствовать коду на реальном языке программирования. Чем детальнее эта связь (чем больше строк в коде Gherkin), тем более развернутым получается тест. Теперь о том, зачем нам развернутый тест.
Основных причины две, первая: «В любом месте реального кода программы может возникнуть ошибка, и мы должны быстро понять - где и почему». Представим, что мы сделали следующую связь:
Код Gherkin(Дано, Когда, Тогда, И)
Код 1С (имена вызываемых процедур)
Дано: Контрагент (покупатель) «Иванов А.В.» оплачивает сумму 1000 рублей. Долг контрагента 500 рублей.
Когда: Фиксируется оплата от контрагента «Иванов А.В.» по договору «Основной» на сумму 1000 рублей
Тогда: Формируется проводка по счету «ВзаиморасчетыСКонтрагентами» на сумму 500 рублей (погашение долга)
И: Формируется проводка по счету «АвансыПолученные» на сумму 500 рублей (фиксируется аванс).
Если у нас возникнет ошибка в процедуре ВыполнитьТест(), то мы как программисты найдем причину. Но нам, скорее всего, понадобится анализ кода, запуск отладчика и тд. А все это наше время. Другое дело, если ошибка возникнет в процедуре «ПроверитьПоводкиПоСчетамАвансовКонтрагентов()», которая сопоставлена в строке Gherkin «И: Формируется проводка по счету «АвансыПолученные» на сумму 500 рублей (фиксируется аванс).». Скорее всего, мы просто заглянем в движения документа и увидим там другую сумму или вообще отсутствие проводок.
Вторая причина, и самая важная: «Мы планируем писать тест до написания программы». И выглядит это следующим образом: у нас уже есть логика на Gherkin, у нас уже есть имена процедур: ПроверитьНаличиеДолгаКонтрагентаПоВзаиморасчетам(), СоздатьПровестиДокументПКО(). Нам остается только зайти в «тело» одноименных процедур и написать там код. Конечно часть процедур нам может не понадобиться в реальной программе. Например «ПроверитьПроводкиПоСчетам() будет нагружать систему, да и если с проводками будет проблема, скорее всего бухгалтер это заметит. А вот другие процедуры, которые будут создавать и проводить документы, мы реально можем использовать. Причем, мы их поместим в общие модули, эти модули отнесем к соответствующим подсистемам и будем вызывать так же, как вызываем их в тестах. Красота и порядок.
Теперь давайте разберемся какие процедуры, с какими строками связывать. В начале раздела, посвященного синтаксису языка Gherkin, указан шаблон истории. Связь реального кода осуществляется только со строками, в которых указаны ключевые слова: «Дано, Когда, Тогда» и детализируются связи с помощью ключевого слова «И».
Напротив ключевого слова «Дано» в квадратных скобках указано «[Ситуация или условие]». Это значит, что на этом этапе проверяются параметры, выполняются запросы к базе данных, сравниваются значения. Это необходимые условия, которые должны быть уже выполнены до начала расчета и создания данных в информационной системе.
Напротив ключевого слова «Когда» в квадратных скобках указано «[Событие или действие]». Это непосредственно расчет и создание данных.
И наконец, напротив ключевого слова «Тогда» в квадратных скобках указано «[Проверка результата]». Это такие же проверки, как и после слова «Дано», только проверяем мы то, что было сделано после ключевого слова «Когда».
Сценарное тестирование через интерфейс пользователя
Сценарное тестирование - это тестирование по предварительно написанному сценарию. Код на языке Gherkin это сценарий, а также отчасти документация и требования.
Но только отчасти, потому что читая такую документацию, пользователь может застрять на первом же «Когда: Фиксируется оплата от контрагента «Иванов А.В.» по договору «Основной» на сумму 1000 рублей». Конечно, эту строку можно развернуть подробнее:
Когда: Создается документ ПКО
И: заполняется реквизит контрагент
И: Заполняется реквизит договор…
Но такие сочинения могут занимать не одну страницу и не один час времени. С одной стороны мы хотим, что бы подготовка таких тестов занимала как можно меньше времени, с другой была как можно более прозрачной и всеобъемлющей. Вопрос - как этого достичь.
Приведу еще пример: В документе ПКО, в модуле формы, в обработчике «ПриИзмененииКонтрагента()» есть проверка, что данный контрагент является физлицом. Такие проверки желательно делать перед записью в модуле объекта, но реальный процесс разработки может диктовать иное. Коля и Вася в какой-то момент времени одновременно дорабатывали один и тот же документ, модуль объекта был захвачен Колей, а Васе нужно было срочно доделать работу. Или задача стояла таким образом: «Выбираемое значение должно проверяться сразу». В результате наш тест этого вообще не выявит, потому что мы создаем документ ПКО программно, не открывая его форму. Мы можем при написании теста программно открывать форму и вообще эмулировать все действия реального пользователя, но объем кода в тесте увеличится в разы. Мы подошли вплотную к проблеме «надо тестировать, но надо разрабатывать, а не тестировать».
В данной ситуации, если мы хотим проверить работу приложения, нам необходимо тестировать интерфейс. Вообще условно разделяют две категории тестирования: на уровне кода и тестирование интерфейса. Причем тестирование интерфейса, это не только пользовательский интерфейс, но и различные сервисы типа Web-сервисов, которые вообще не имеют графического интерфейса. Если говорить о тестировании графических интерфейсов, то идеальным решением было бы использовать специальные программные средства и инструменты.
Основная цель таких продуктов – это ускорить и упорядочить процесс написания тестов. Этот процесс должен стать максимально прозрачным и простым. В сфере автоматизации тестирования через графический интерфейс, можно выделить два основных вида инструментов:
- Которые взаимодействуют с интерфейсом приложения на уровне программного кода. Это выглядит примерно так же, если бы мы писали код открывающий формы и нажимающий кнопки, только у нас были бы генераторы этого кода. Мы бы нажимали на кнопку «Ок», а в модуле появлялась строка типа ТекущаяФорма.Кнопки.Ок.Нажать(). Но для того чтобы реализовать данную возможность, разработчик приложения должен заранее задуматься о предоставлении такого интерфейса.
- Которые взаимодействуют с интерфейсом через драйвера устройств ввода данных и используют механизмы распознания изображений. Это выглядит примерно так: программа ищет на экране конкретное изображение, если она его находит, то эмулирует клики мышки в конкретную область изображения и начитает ввод данных с клавиатуры. Данный подход не зависит от того, предоставил ли разработчик приложения такую возможность или нет. Но недостатком является то, что могут возникать ошибки при распознавании изображений, есть зависимость от разрешения экрана (оно должно быть неизменным) и скорость работы таких тестов ниже, так как на распознавание изображений уходит определенное время.
В поисках решения я обратился ко второму виду инструментов, которые имеют общепринятое название «Image-based testing». Здесь оказался хороший выбор от навороченных и дорогих, типа «TestComplete», до простых и полностью бесплатных типа «SikuliX». Многие из этих продуктов сами имеют программный интерфейс, начиная от взаимодействия через командную строку, до встроенных интерпретаторов типа «Python». Основная идея для искателей решений данной проблемы, это обеспечить взаимодействие этих продуктов с платформой 1С, чем я уже занялся и в ближайшее время надеюсь предоставить результаты. Так же надеюсь, что возможно кто-то это уже сделал и поделится своими идеями.
Ну а если для вас управляемый интерфейс это родное или вы уже придумали как быстро взаимодействовать с обычными формами, обратите внимание на продукт под названием «Vanessa Behavior». Он бесплатный и очень быстро развивается. Есть хороший видео обзор Повторное использование кода тестов в других сценариях
Данный пункт – это высший пилотаж, но к нему по любому приходят все, кто всерьез занимается автоматизацией тестирования. Основная идея – использовать этапы одного теста в других тестах. То есть мы собираем некую библиотеку, в которой хранятся часто используемые действия, скажем по созданию и заполнению конкретных видов документов, формированию отчетов, проверке движений и тд.
Опять же, если говорить о готовых решениях, то в «Vanessa Behavior» это тоже реализовано. На мой взгляд, данный проект весьма перспективен и заслуживает поддержки.
Всем спасибо за внимание!
Глоссарий
Software development methodology (SDM) – Так же известны как software development life cycle, software development process, software process. Методологии деления процесса разработки программного обеспечения на отдельные фазы или этапы, каждый из которых содержит меры улучшающие планирование и управление процессом разработки в целом. В качестве примеров можно привести: «Каскадную модель» (waterfall model), Прототипное программирование (prototyping), СпираL9;льная модель (spiral model), быстрая разработка приложений(rapid application development), экстемальное программирование (extreme programming), различные agile-методы (agile methodology) и тд. (Wikipedia)
Agile software development. - Гибкая методология разработки (agile-методы)— серия подходов к разработке программного обеспечения, ориентированных на использование итеративной разработки, динамическое формирование требований и обеспечение их реализации в результате постоянного взаимодействия внутри самоорганизующихся рабочих групп, состоящих из специалистов различного профиля. Существует несколько методик, относящихся к классу гибких методологий разработки, в частности «экстремальное программирование», «DSDM», «Scrum», «FDD». (Wikipedia)
Domain-driven design (DDD).
Предметно - ориентированное проектирование. Это набор принципов и схем, направленных на создание оптимальных систем объектов. Сводится к созданию программных абстракций, которые называются моделями предметных областей. В эти модели входит бизнес-логика, устанавливающая связь между реальными условиями области применения продукта и кодом. Предметно-ориентированное проектирование не является какой-либо конкретной технологией или методологией. Это набор правил, которые позволяют принимать правильные проектные решения. Данный подход позволяет значительно ускорить процесс проектирования программного обеспечения в незнакомой предметной области. Есть книга - Эрик Эванс (Eric Evans) «Проблемно-ориентированное проектирование». (Wikipedia)
Feature-driven development (FDD). – Разработка управляемая функциональностью. Итеративная методология разработки программного обеспечения, одна из гибких методологий разработки (agile). FDD представляет собой попытку объединить наиболее признанные в индустрии разработки программного обеспечения методики, принимающие за основу важную для заказчика функциональность (свойства) разрабатываемого программного обеспечения. Основной целью данной методологии является разработка реального, работающего программного обеспечения систематически, в поставленные сроки. (Wikipedia)
Test-driven development (TDD). – Разработка через тестирование. Техника разработки программного обеспечения, которая основывается на повторении очень коротких циклов разработки: сначала пишется тест, покрывающий желаемое изменение, затем пишется код, который позволит пройти тест, и под конец проводится рефакторинг нового кода к соответствующим стандартам. Кент Бек, считающийся изобретателем этой техники, утверждал в 2003 году, что разработка через тестирование поощряет простой дизайн и внушает уверенность (inspires confidence). В 1999 году при своём появлении разработка через тестирование была тесно связана с концепцией «сначала тест» (test-first), применяемой в «экстремальном программировании» (agile методология), однако позже выделилась как независимая методология. (Wikipedia)
behavior-driven development (BDD). - Разработка основанная на функционировании. Процесс разработки программного обеспечения, который возник из TDD. Объединяет главные техники и принципы TDD, идеи из DDD и OOAD (техника объектно ориентированного анализа и проектирования). BDD главным образом является идеологией о том, как разработке программного обеспечения быть одновременно понятной бизнесу и техническим специалистам. В ней используются специализированные программные инструментарии для разработки программного обеспечения. И не смотря на то, что эти инструментарии используются в основном в BDD проектах, они так же могут быть использованы для поддержки TDD. (Wikipedia)
Благодаря классному дядьке Кенту Беку (Kent Beck) родилась замечательная методология test-driven development. Не смотря на необычность подхода, переворачивающего привычный процесс написания кода с ног на голову (тест на функционал создается до реализации), сейчас уже можно сказать, что разработка через тестирование стала стандартом де-факто. Практически в любых вакансиях фигурирует требование к знанию и опыту использования методики TDD и соответствующих инструментов. Почему, казалось бы, ломающая привычную парадигму мышления методология прижилась и стандартизировалась? Потому что “Жизнь слишком коротка для ручного тестирования”, а писать авто-тесты на существующий код иногда просто не возможно, ведь код, написанный в обычной парадигме, как правило совершенно тесто-не-пригодный.
Стоит отметить, что за время своего существования методология успела обзавестись ответвлением (fork) в виде BDD. Дэн Норт (Dan North) в своей статье (Introducing BDD) указал на сложности внедрения TDD среди разработчиков и для решения обозначенных проблем предложил практику, которая называется behaviour-driven development. Основной фишкой BDD можно назвать микс из TDD и DDD, которая в начале выражалась в правильном именовании тестовых методов (названия тестовых методов должны быть предложениями). Апогеем BDD, на текущий момент, можно считать рождение языка Gherkin и инструментария, который его использует (Cucumber, RSpec и т.п.).
К чему я веду и при чем тут 1С?
-
— вполне себе зрелый проект, позволюящий разрабатывать в стиле TDD. — спецификации на языке Gherkin и т.п., пока что не в релизном состоянии.
Прежде чем ответить на этот вопрос, я хочу коснуться темы хорошо написанных утверждений в тестах. Утверждения обозначают ожидаемое поведение нашего кода. Одного взгляда на утверждения должно быть достаточно, чтобы понять, какое поведение тест пытается до нас донести. К сожалению, классические утверждения не позволяют этого достичь. Зачастую нам приходится долго вчитываться и расшифровывать замысел автора теста.
К счастью, в последнее время появилась тенденция к применению текучих интерфейсов (fluent interface), что очень положительно сказывается на наглядности и интуитивной понятности кода. Инструментарий для тестирования так же не остался в стороне.оявились текучие утверждения, называемые так же утверждениями в стиле BDD. Они позволяют формулировать утверждения в более естественной, удобной и выразительной манере.
Впервые я столкнулся с подобным подходом в NUnit в модели утверждений на основе ограничений (Constraint-Based Assert Model).
Много позже я познакомился со связкой mocha.js + chai.js, которая у меня вызвала полнейший восторг.
Так вот, мой ответ на вопрос “Как лично я могу помочь миру 1С разработки перейти на передовые методологии?” — текучие утверждения… для начала.
Разработка текучих утверждений для платформы 1С
Как заправский разработчик через тестирование, я начал разработку с теста. Первый тестовый метод содержал всего 1 строку:
- Что(ПроверяемоеЗначение) — сохраняет в контексте объекта-утверждения проверяемое значение;
- Равно(ОжидаемоеЗначение) — проверяет на равенство ранее сохраненное значение с переданным ожидаемым значением. В случае неравенства выбрасывается исключение с описанием ошибки утверждения.
Далее я задумался над тем, что делать с утверждением НеРавно. Должно ли быть такое утверждение? В классических утверждениях так и есть, почти каждое утверждение имеет своего антипода (Равно/НеРавно, Заполнено/НеЗаполнено и т.д.). Но только не в текучих утверждениях! Так родился тест №2:
Выглядит красиво, но не реализуемо на языке 1С. Еще попытка:
По прежнему красиво и казалось бы реализуемо. Нужно всего лишь взвести флаг отрицания в контексте объекта-утверждения, и затем любое следующее по цепи утверждение проверять с учетом этого флага. По сути нужен был XOR, на языке 1С это выглядит вот так:
Но платформа отказалась компилировать объект с методом Не(). Дело в том, что Не — зарезервированное слово, ограничение на его использование распространяется в т.ч. и на имя метода. Мозговой штурм с коллегами не позволили красиво обойти эту проблему, поэтому финальный вариант с отрицанием выглядит так:
Если кто-то предложит лучшее решение обозначенной проблемы, я буду очень признателен. Вариант замены русских букв на латиницу не предлагать!
В итоге родился следующий API
Не_() — отрицает любое утверждение следующее по цепи.
ЭтоИстина() — утверждает, что проверяемое значение является Истиной.
ЭтоЛожь() — утверждает, что проверяемое значение является Ложью.
Равно(ОжидаемоеЗначение) — утверждает, что проверяемое значение равно ожидаемому.
Больше(МеньшееЗначение) — утверждает, что проверяемое значение больше, чем переданное в утверждение.
БольшеИлиРавно(МеньшееИлиРавноеЗначение) / Минимум(МинимальноеЗначение) — утверждает, что проверяемое значение больше или равно переданному в утверждение.
МеньшеИлиРавно(БольшееИлиРавноеЗначение) / Максимум(МаксимальноеЗначение) — утверждает, что проверяемое значение меньше или равно переданному в утверждение.
Меньше(БольшееЗначение) — утверждает, что проверяемое значение меньше, чем переданное в утверждение.
Заполнено() — утверждает, что проверяемое значение отличается от значения по умолчанию того же типа.
Существует() — утверждает, что проверяемое значение не Null и не Неопределено.
ЭтоНеопределено() — утверждает, что проверяемое значение это Неопределено.
ЭтоNull() — утверждает, что проверяемое значение это Null.
ИмеетТип(Тип) — утверждает, что проверяемое значение имеет переданный в утверждение тип или имя типа.
Между(НачальноеЗначение, КонечноеЗначение) — утверждает, что проверяемое значение находится между переданными в утверждение значениями.
Содержит(ИскомоеЗначение) — утверждает, что проверяемое значение содержит переданное в утверждение. Применяется для строк и коллекций.
ИмеетДлину(ОжидаемаяДлина) — утверджает, что проверяемое значение имеет длину переданную в утверждение. Применяется для строк и коллекций.
Благодаря классному дядьке Кенту Беку (Kent Beck) родилась замечательная методология test-driven development. Не смотря на необычность подхода, переворачивающего привычный процесс написания кода с ног на голову (тест на функционал создается до реализации), сейчас уже можно сказать, что разработка через тестирование стала стандартом де-факто. Практически в любых вакансиях фигурирует требование к знанию и опыту использования методики TDD и соответствующих инструментов. Почему, казалось бы, ломающая привычную парадигму мышления методология прижилась и стандартизировалась? Потому что “Жизнь слишком коротка для ручного тестирования”, а писать авто-тесты на существующий код иногда просто не возможно, ведь код, написанный в обычной парадигме, как правило совершенно тесто-не-пригодный.
Стоит отметить, что за время своего существования методология успела обзавестись ответвлением (fork) в виде BDD. Дэн Норт (Dan North) в своей статье (Introducing BDD) указал на сложности внедрения TDD среди разработчиков и для решения обозначенных проблем предложил практику, которая называется behaviour-driven development. Основной фишкой BDD можно назвать микс из TDD и DDD, которая в начале выражалась в правильном именовании тестовых методов (названия тестовых методов должны быть предложениями). Апогеем BDD, на текущий момент, можно считать рождение языка Gherkin и инструментария, который его использует (Cucumber, RSpec и т.п.).
К чему я веду и при чем тут 1С?
-
— вполне себе зрелый проект, позволюящий разрабатывать в стиле TDD. — спецификации на языке Gherkin и т.п., пока что не в релизном состоянии.
Прежде чем ответить на этот вопрос, я хочу коснуться темы хорошо написанных утверждений в тестах. Утверждения обозначают ожидаемое поведение нашего кода. Одного взгляда на утверждения должно быть достаточно, чтобы понять, какое поведение тест пытается до нас донести. К сожалению, классические утверждения не позволяют этого достичь. Зачастую нам приходится долго вчитываться и расшифровывать замысел автора теста.
К счастью, в последнее время появилась тенденция к применению текучих интерфейсов (fluent interface), что очень положительно сказывается на наглядности и интуитивной понятности кода. Инструментарий для тестирования так же не остался в стороне.оявились текучие утверждения, называемые так же утверждениями в стиле BDD. Они позволяют формулировать утверждения в более естественной, удобной и выразительной манере.
Впервые я столкнулся с подобным подходом в NUnit в модели утверждений на основе ограничений (Constraint-Based Assert Model).
Много позже я познакомился со связкой mocha.js + chai.js, которая у меня вызвала полнейший восторг.
Так вот, мой ответ на вопрос “Как лично я могу помочь миру 1С разработки перейти на передовые методологии?” — текучие утверждения… для начала.
Разработка текучих утверждений для платформы 1С
Как заправский разработчик через тестирование, я начал разработку с теста. Первый тестовый метод содержал всего 1 строку:
- Что(ПроверяемоеЗначение) — сохраняет в контексте объекта-утверждения проверяемое значение;
- Равно(ОжидаемоеЗначение) — проверяет на равенство ранее сохраненное значение с переданным ожидаемым значением. В случае неравенства выбрасывается исключение с описанием ошибки утверждения.
Далее я задумался над тем, что делать с утверждением НеРавно. Должно ли быть такое утверждение? В классических утверждениях так и есть, почти каждое утверждение имеет своего антипода (Равно/НеРавно, Заполнено/НеЗаполнено и т.д.). Но только не в текучих утверждениях! Так родился тест №2:
Выглядит красиво, но не реализуемо на языке 1С. Еще попытка:
По прежнему красиво и казалось бы реализуемо. Нужно всего лишь взвести флаг отрицания в контексте объекта-утверждения, и затем любое следующее по цепи утверждение проверять с учетом этого флага. По сути нужен был XOR, на языке 1С это выглядит вот так:
Но платформа отказалась компилировать объект с методом Не(). Дело в том, что Не — зарезервированное слово, ограничение на его использование распространяется в т.ч. и на имя метода. Мозговой штурм с коллегами не позволили красиво обойти эту проблему, поэтому финальный вариант с отрицанием выглядит так:
Если кто-то предложит лучшее решение обозначенной проблемы, я буду очень признателен. Вариант замены русских букв на латиницу не предлагать!
В итоге родился следующий API
Не_() — отрицает любое утверждение следующее по цепи.
ЭтоИстина() — утверждает, что проверяемое значение является Истиной.
ЭтоЛожь() — утверждает, что проверяемое значение является Ложью.
Равно(ОжидаемоеЗначение) — утверждает, что проверяемое значение равно ожидаемому.
Больше(МеньшееЗначение) — утверждает, что проверяемое значение больше, чем переданное в утверждение.
БольшеИлиРавно(МеньшееИлиРавноеЗначение) / Минимум(МинимальноеЗначение) — утверждает, что проверяемое значение больше или равно переданному в утверждение.
МеньшеИлиРавно(БольшееИлиРавноеЗначение) / Максимум(МаксимальноеЗначение) — утверждает, что проверяемое значение меньше или равно переданному в утверждение.
Меньше(БольшееЗначение) — утверждает, что проверяемое значение меньше, чем переданное в утверждение.
Заполнено() — утверждает, что проверяемое значение отличается от значения по умолчанию того же типа.
Существует() — утверждает, что проверяемое значение не Null и не Неопределено.
ЭтоНеопределено() — утверждает, что проверяемое значение это Неопределено.
ЭтоNull() — утверждает, что проверяемое значение это Null.
ИмеетТип(Тип) — утверждает, что проверяемое значение имеет переданный в утверждение тип или имя типа.
Между(НачальноеЗначение, КонечноеЗначение) — утверждает, что проверяемое значение находится между переданными в утверждение значениями.
Содержит(ИскомоеЗначение) — утверждает, что проверяемое значение содержит переданное в утверждение. Применяется для строк и коллекций.
ИмеетДлину(ОжидаемаяДлина) — утверджает, что проверяемое значение имеет длину переданную в утверждение. Применяется для строк и коллекций.
Читайте также: