Статьи

BDD, автоматические приемочные тесты и непрерывная доставка: работа со сценариями, которые находятся в стадии разработки

Одним из основных правил непрерывной интеграции (и непрерывной доставки) является то, что вы никогда не должны сознательно фиксировать код, который нарушит сборку. Когда вы практикуете разработку через тестирование, это легко: вы пишете провальный тест (или, точнее, проваленную «исполняемую спецификацию»), делаете его успешным, а затем реорганизуете по мере необходимости. Вы фиксируете свой код только после того, как вы реорганизовали и выполнили все свои модульные тесты, чтобы убедиться, что вы случайно не нарушили ничего в другом месте кода.

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

Общий принцип CI по-прежнему применяется для автоматических приемочных тестов — вы никогда не должны сознательно фиксировать код, который нарушает один на сервере сборки. Когда люди делают это, это неизбежно приводит к непрерывному потоку сломанных сборок, которые люди игнорируют, потому что это считается нормальным положением дел. Не существует простого способа узнать, не нарушена ли сборка из-за регрессии или из-за того, что «выполняется» приемочный тест. В этих условиях КИ имеет очень мало значения. Отчет о статусе становится ошибочным. Если возникают «реальные» проблемы регрессии, они обнаруживаются и исправляются медленнее. И любая попытка непрерывной доставки становится невозможной, поскольку вы никогда не сможете достоверно узнать, когда сборка готова к выпуску в производство.

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

Пометка приемочных испытаний

Один из распространенных подходов, используемых с такими инструментами, как JBehave, Cucumber и SpecFlow, состоит в том, чтобы пометить приемочные тесты, которые находятся в стадии разработки, и настроить сборку Continuous Integration для запуска только историй без тега незавершенного производства. Например, следующий сценарий JBehave использует тег @wip, чтобы отметить сценарий, который находится в стадии разработки:

User Authentication

Narrative:
In order to prevent unauthorized use of member points
As the system admin
I want users to authenticate before they can access their account

Meta:
@wip

Scenario: Successful authentication
Given Jane is a registered Frequent Flyer
When Jane authenticates with a valid email address and password
Then Jane should be given access to her account

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

Особые ветви

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

Для команд, которые все еще используют централизованные системы управления версиями, это немного более сдерживает, так как ветвление и объединение с использованием таких инструментов, как Subversion, может быть болезненным процессом, а концепция локальной ветки вообще не существует. Но все же может быть жизнеспособным вариантом. , Хитрость заключается в том, чтобы не дать ветке жить слишком долго (например, более пары дней), потому что долгоживущие ветки создают риск проблем интеграции в будущем.

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

Инкрементная реализация

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

Для больших изменений вы можете использовать немного другой подход. Обычно это включает в себя создание новой функции изолированно, поддерживая существующее решение, пока вы не будете готовы полностью заменить его. Например, предположим, что вам нужно заменить модуль обработки платежей в вашем приложении. Это большая часть работы, которую вы не сможете выполнить за один присест. Первое, что вы делаете, это изолируете модуль обработки платежей, например, с помощью интерфейса (если вы используете инфраструктуру внедрения зависимостей, такую ​​как Spring или Guice, это может быть уже сделано как часть вашей обычной работы по разработке). Затем вы создаете альтернативную реализацию модуля в соответствии с новыми или измененными требованиями, используя TDD для разработки и реализации. Ваши новые приемочные тесты используют новый модуль; как только все это пройдет,Вы готовы заменить старую реализацию новой.

Этот подход похож на идею «Feature Toggles», предложенную Мартином Фаулером, но гораздо проще в реализации. Это делает возможным работать непосредственно с главной ветвью, хотя это не уменьшит риск проблем интеграции, если разработка займет слишком много времени.

Вывод

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

 — специалист по BDD, автоматизированному тестированию и оптимизации жизненного цикла программного обеспечения, а также автор книги  BDD in Action  и других книг. Джон работает регулярные курсы  в Австралии, Лондоне и Европе по темам , связанным с такими , как  Agile сбор требованийповедение Driven DevelopmentTest Driven Development и автоматизированного тестирования приема .