Введение в BDD
Разработка на основе поведений с применением SpecFlow и WatiN
Брэндон Сэтром
По мере распространения автоматизированного модульного тестирования (unit testing) в разработке программного обеспечения то же самое происходит и с различными способами «сначала тест» (test-first methods). Каждая из этих методик открывает уникальный набор возможностей группам разработки и ставит перед ними свои проблемы, но все они нацелены на «тестирование как часть проектирования».
Однако в эпоху «сначала тестирование» поведение пользователя выражалось в основном через модульные тесты, написанные на языке системы, т. е. на языке, непонятном пользователю. С появлением методик разработки на основе поведений (Behavior-Driven Development, BDD) эта динамика меняется. Используя методики BDD, вы можете создавать автоматизированные тесты на языке бизнеса, в то же время сохраняя связь с реализуемой системой.
Конечно, был создан целый ряд инструментов, помогающих реализовать BDD в процессе разработки. К ним относятся Cucumber в Ruby, а также SpecFlow и WatiN для Microsoft .NET Framework. SpecFlow упрощает написание и выполнение спецификаций в Visual Studio, а WatiN позволяет управлять браузером для комплексного автоматизированного тестирования системы.
В этой статье я дам краткий обзор BDD, а затем поясню, как цикл BDD обертывает цикл традиционной разработки, управляемой тестами (Test-Driven Development, TDD), тестами уровня конкретной функциональности (далее — функциями), которые управляют реализацией уровня модулей. Подготовив почву для методов «сначала тестирование», я ознакомлю вас с SpecFlow и WatiN и покажу примеры того, как можно использовать эти инструменты совместно с MSTest для реализации BDD в ваших проектах.
Краткая история автоматизированного тестирования
Одна из наиболее ценных методик, родившихся в рамках инициативы Agile Software (гибкое ПО), — автоматизированная разработка в стиле «сначала тест», которую часто называют разработкой, управляемой тестами (Test-Driven Development, TDD). Основополагающий принцип TDD заключается в том, что тест — это не только руководство по проектированию и разработке; он в равной мере обеспечивает верификацию и регрессию. Тест также определяет модуль с необходимой функциональностью и потом используется для написания лишь того кода, который необходим для получения этой функциональности. Поэтому первый шаг в реализации любой новой функциональности — описание ваших ожиданий с помощью заведомо неуспешного теста (failing test) (рис. 1).
Рис.1. Цикл разработки, управляемой тестами (TDD)
Немалая часть разработчиков и групп добилась большого успеха, используя TDD. Но другая часть — нет.Они часто обнаруживали, что со временем им все труднее управлять процессом, особенно при разрастании объема тестов, при котором эти тесты начинали деградировать. Некоторые не совсем уверены, как приступать к разработке с применением TDD, а кому-то легко начать TDD, но по мере приближения сроков от такой разработки приходится отказываться в авральном режиме. Наконец, многие заинтересованные разработчики сталкиваются с противодействием их задумкам внутри организаций — то ли из-за того, что слово «тест» намекает на принадлежность функции другой группе, то ли из-за неправильного понимания того, что TDD якобы приводит к созданию слишком большого количества кода и замедлению работы над проектами.
Стив Фримен (Steve Freeman) и Нэт Прайс (Nat Pryce) в своей книге «Growing Object-Oriented Software, Guided by Tests» (Addison-Wesley Professional, 2009) отмечают, что «традиционной» TDD не хватает некоторых преимуществ истинной разработки по принципу «сначала тест».Вот небольшая цитата из их книги.
«Возникает соблазн начать процесс TDD с написания модульных тестов для классов в приложении. Это лучше, чем полное отсутствие тестов, и позволяет отловить основные ошибки программирования, о которых нам всем хорошо известно, но которых так трудно избежать… Однако проект только с модульными тестами не получает крайне важных преимуществ TDD. Нам попадались проекты с высококачественным кодом, тщательно тестируемым по модулям, который, как потом выяснялось, ниоткуда не вызывался или же он не был интегрирован с остальной частью системы и в итоге подлежал полному переписыванию».
В 2006 году Дэн Норт (Dan North) документировал многие из этих проблем в статье в журнале «Better Software» ((blog.dannorth.net/introducing-bdd). В этой статье он описал ряд методик, которые он применял за предшествующие три года. Эти методики, хоть и являлись TDD по определению, привели его к принятию тестирования с большей ориентацией на анализ; в итоге он придумал термин «Behavior-Driven Development», который заключал в себе суть этих перемен.
В одном из распространенных применений BDD предпринимается попытка расширить TDD сужением фокуса и ужесточением процесса создания тестов через Acceptance Tests (приемочные тесты), или исполняемые спецификации (executable specifications). Каждая спецификация действует как входная точка в цикл разработки и описывает, как должна вести себя система с точки зрения пользователя (в пошаговом виде). После этого разработчик использует спецификацию и существующий процесс TDD для реализации ровно такого количества производственного кода, которого достаточно для получения базового сценария (рис. 2).
Рис. 2 Цикл разработки на основе поведений (BDD)
Где начинается проектирование
Многие считают BDD надмножеством TDD, но не его заменой. Ключевая разница — фокусировка на начальном проекте и создании тестов. Но основное внимание уделяется не тестам модулей или объектов, как в TDD, а целям пользователей и пошаговым операциям, предпринимаемым ими для достижения этих целей. Поскольку я больше не начинаю с тестов малых модулей, я менее склонен размышлять над деталями проекта или использованию более мелких частей. Вместо этого я документирую исполняемые спецификации, которые контролируют мою систему. Я по-прежнему пишу модульные тесты, но в BDD поощряется подход «от внешнего к внутреннему» (outside-in approach), который начинается с полного описания подлежащей реализации функции.
Давайте рассмотрим пример этого различия. В традиционной практике TDD вы могли бы написать тест (рис. 3) для проверки метода Create объекта CustomersController.
Рис.3. Модульный тест для создания объекта клиента
[TestMethod]
public void PostCreateShouldSaveCustomerAndReturnDetailsView() {
var customersController = new CustomersController();
var customer = new Customer {
Name = "Hugo Reyes",
Email = "hreyes@dharmainitiative.com",
Phone = "720-123-5477"
};
var result = customersController.Create(customer) as ViewResult;
Assert.IsNotNull(result);
Assert.AreEqual("Details", result.ViewName);
Assert.IsInstanceOfType(result.ViewData.Model, typeof(Customer));
customer = result.ViewData.Model as Customer;
Assert.IsNotNull(customer);
Assert.IsTrue(customer.Id > 0);
}
В случае TDD это обычно один из первых тестов. Я проектирую открытый API для своего объекта CustomersController, указывая ожидания того, как он должен вести себя. В случае BDD я все равно пишу этот тест, но не первым. Вместо этого я переношу фокус внимания на функциональность уровня функции (feature), расписывая нечто вроде того, что показано на рис. 4. Затем я использую этот сценарий как руководство при реализации каждого модуля кода, необходимого для успешного прохождения этого сценария.
Рис.4. Спецификация уровня функции
Feature: Create a new customer
In order to improve customer service and visibility
As a site administrator
I want to be able to create, view and manage customer records
Scenario: Create a basic customer record
Given I am logged into the site as an administrator
When I click the "Create New Customer" link
And I enter the following information
| Field | Value |
| Name | Hugo Reyes |
| Email | hreyes@dharmainitiative.com |
| Phone | 720-123-5477 |
And I click the "Create" button
Then I should see the following details on the screen:
| Value |
| Hugo Reyes |
| hreyes@dharmainitiative.com |
| 720-123-5477 |
Это внешний цикл на рис. 2 (неуспешный приемочный тест). Как только этот тест создан и завершен неудачно, я реализую каждый шаг в каждом сценарии моей функции (feature), следуя внутреннему циклу TDD, также показанному на рис. 2. В случае CustomersController на рис. 3 я напишу этот тест после того, как доберусь до соответствующего этапа в реализации своей функции, но до реализации логики контроллера, необходимой для успешного прохождения теста этого этапа.
BDD и автоматизированное тестирование
С самого начала сообщество BDD искало способ обеспечения того же уровня автоматизации тестирования с приемочными тестами, который уже какое-то время является нормой в модульном тестировании. Один из примечательных примеров — Cucumber (cukes.info), средство тестирования на основе Ruby, которое выражает создание приемочных тестов уровня функции (feature), написанных на «понятном бизнесу языке предметной области».
Тесты Cucumber пишутся с применением синтаксиса User Story (пользовательская история) для каждого файла функции (feature file) и с синтаксисом Given, When, Then (GWT) для каждого сценария. (Подробнее о синтаксисе User Story см. по ссылке c2.com/cgi/wiki?UserStory.) GWT описывает текущий контекст сценария (Given), операции, выполняемые как часть теста (When) и ожидаемые видимые результаты (Then). Функция на рис. 4 является примером такого синтаксиса.
В Cucumber файлы функции на языке пользователя анализируются, и каждый этап сценария соответствует коду на Ruby, который использует открытые интерфейсы рассматриваемой системы и определяет, проходит ли проверку этот этап.
Инновационные достижения последних лет, позволяющие использовать сценарии как автоматизированные тесты, распространились и на экосистему .NET Framework. У разработчиков теперь есть инструменты, позволяющие писать спецификации на том же структурированном английском синтаксисе, что и в Cucumber, которые можно потом использовать как тесты, проверяющие код. Такие BDD-средства тестирования, как SpecFlow (specflow.org), Cuke4Nuke ((github.com/richardlawrence/Cuke4Nuke) и другие, позволяют создавать в процессе сначала исполняемые спецификации, использовать их по мере написания функциональности и заканчивать с документированной функцией (feature), прямо увязанной с вашим процессом разработки и тестирования.
Начинаем работу с SpecFlow и WatiN
В этой статье я буду использовать SpecFlow для тестирования приложения на основе шаблона Model-View-Controller (MVC). Чтобы начать работу с SpecFlow, нужно его скачать и установить. После установки SpecFlow создайте новое приложение ASP.NET MVC с проектом модульных тестов. Я предпочитаю, чтобы в моем проекте модульных тестов содержались именно тесты модулей (тесты контроллера, хранилища и т. д.), поэтому я также создаю проект приемочных тестов AcceptanceTests для тестов SpecFlow.
После включения проекта AcceptanceTests и добавления ссылки на сборку TechTalk.SpecFlow добавьте новую Feature, используя Add | New Item Templates, создаваемые SpecFlow при установке, и присвойте ей имя CreateCustomer.feature.
Заметьте, что этот файл создается с расширением .feature и что Visual Studio распознает его как поддерживаемый благодаря интегрируемому инструментарию SpecFlow. Также обратите внимание на то, что с файлом вашей функции сопоставлен файл отделенного кода (code-behind file) с расширением .cs. Всякий раз, когда вы сохраняете файл .feature, SpecFlow разбирает его содержимое и преобразует текст из этого файла в своего рода «испытательный стенд» (test fixture). Этот «испытательный стенд» представлен кодом в связанном файле .cs, и именно этот код выполняется всякий раз, когда вы запускаете свой набор тестов.
По умолчанию SpecFlow использует NUnit в качестве исполняющей среды тестов (test-runner), но также поддерживает MSTest — нужно лишь внести небольшие изменения в конфигурацию, добавив к проекту тестов файл app.config со следующими элементами:
<configSections>
<section name="specFlow"
type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow"/>
</configSections>
<specFlow>
<unitTestProvider name="MsTest" />
</specFlow>
Ваш первый приемочный тест
Когда вы создаете новую функцию (feature), SpecFlow заполняет ее файл текстом по умолчанию, иллюстрируя синтаксис, применяемый для описания функции. Замените текст по умолчанию в своем файле CreateCustomer.feature текстом с рис. 4.
Каждый файл функции состоит из двух частей. Первая часть — имя и описание функции, где применяется синтаксис User Story для описания роли пользователя, его цели и типов операций, которые нужно выполнять пользователю, чтобы добиться указанной цели в системе. Этот раздел требуется SpecFlow для автоматической генерации тестов, но само содержимое не используется в этих тестах.
Вторая часть — это один или более сценариев. Каждый сценарий используется для генерации метода теста в сопоставленном файле .feature.cs, как показано на рис. 5, и каждый этап в сценарии передается в исполняющую среду SpecFlow, которая сопоставляет этот этап через регулярное выражение с записью в файле SpecFlow, который называется файлом определения этапа (Step Definition file).
Рис.5. Метод теста, генерируемый SpecFlow
public virtual void CreateABasicCustomerRecord() {
TechTalk.SpecFlow.ScenarioInfo scenarioInfo =
new TechTalk.SpecFlow.ScenarioInfo(
"Create a basic customer record", ((string[])(null)));
this.ScenarioSetup(scenarioInfo);
testRunner.Given(
"I am logged into the site as an administrator");
testRunner.When("I click the \"Create New Customer\" link");
TechTalk.SpecFlow.Table table1 =
new TechTalk.SpecFlow.Table(new string[] {
"Field", "Value"});
table1.AddRow(new string[] {
"Name", "Hugo Reyesv"});
table1.AddRow(new string[] {
"Email", "hreyes@dharmainitiative.com"});
table1.AddRow(new string[] {
"Phone", "720-123-5477"});
testRunner.And("I enter the following information",
((string)(null)), table1);
testRunner.And("I click the \"Create\" button");
TechTalk.SpecFlow.Table table2 =
new TechTalk.SpecFlow.Table(new string[] {
"Value"});
table2.AddRow(new string[] {
"Hugo Reyes"});
table2.AddRow(new string[] {
"hreyes@dharmainitiative.com"});
table2.AddRow(new string[] {
"720-123-5477"});
testRunner.Then("I should see the following details on screen:",
((string)(null)), table2);
testRunner.CollectScenarioErrors();
}
Определив свою первую функцию, нажмите Ctrl+R, T для запуска тестов SpecFlow. Ваш тест CreateCustomer закончится неудачей как незавершенный, так как SpecFlow не сможет найти соответствующее определение для первого этапа в вашем тесте (рис. 6). Заметьте, что исключение происходит в файле .feature, а не в связанном с ним файле отделенного кода.
Рис. 6. SpecFlow не может найти определение этапа
Поскольку вы еще не создали файл определения этапа, это исключение ожидаемое. Щелкните OK в диалоге исключения и найдите тест CreateABasicCustomerRecord в окне Visual Studio Test Results. Если соответствующий этап не найден, SpecFlow использует ваш файл функции для генерации кода, необходимого в файле определения вашего этапа; вы можете скопировать этот код и использовать его, приступая к реализации этапа.
В проекте AcceptanceTests создайте файл определения этапа, используя шаблон SpecFlow Step Definition, и присвойте ему имя CreateCustomer.cs. Затем скопируйте вывод из SpecFlow в этот класс. Вы заметите, что каждый метод дополняется одним из атрибутов SpecFlow, который помечает метод как этап Given, When или Then и предоставляет RegEx, сопоставляющее метод с этапом в файле функции.
Интеграция WatiN для тестирования через браузер
Отчасти цель использования BDD заключается в создании набора автоматизированных тестов, которые проверяют максимально возможный объем функциональности всей системы. Поскольку я создаю приложение ASP.NET MVC, я могу использовать средства, помогающие писать сценарии для веб-браузера, чтобы он взаимодействовал с моим сайтом.
Одно из таких средств — WatiN, библиотека с открытым исходным кодом для автоматизации тестирования через веб-браузер. Вы можете скачать WatiN с from watin.sourceforge.net и добавить ссылку на WatiN.Core в свой проект AcceptanceTests.
Основной способ взаимодействия с WatiN — через объект браузера (либо IE(), либо FireFox() в зависимости от того, какой именно браузер вы предпочитаете), который предоставляет открытый интерфейс для управления экземпляром установленного браузера. Поскольку вы должны проходить браузер через несколько этапов в сценарии, вам нужен некий способ передачи того же объекта браузера между этапами в классе определения этапа. С этой целью я обычно создаю статический класс WebBrowser как часть своего проекта AcceptanceTests и использую его для работы с IE-объектом в WatiN и ScenarioContext, который применяется SpecFlow для сохранения состояния между этапами в сценарии:
public static class WebBrowser {
public static IE Current {
get {
if (!ScenarioContext.Current.ContainsKey("browser"))
ScenarioContext.Current["browser"] = new IE();
return ScenarioContext.Current["browser"] as IE;
}
}
}
Первый этап, реализуемый вами в CreateCustomer.cs, — Given, который начинает тест, регистрируя пользователя как администратора сайта:
[Given(@"I am logged into the site as an administrator")]
public void GivenIAmLoggedIntoTheSiteAsAnAdministrator() {
WebBrowser.Current.GoTo(http://localhost:24613/Account/LogOn);
WebBrowser.Current.TextField(Find.ByName("UserName")).TypeText("admin");
WebBrowser.Current.TextField(Find.ByName("Password")).TypeText("pass123");
WebBrowser.Current.Button(Find.ByValue("Log On")).Click();
Assert.IsTrue(WebBrowser.Current.Link(Find.ByText("Log Off")).Exists);
}
Помните, что часть Given сценария предназначена для настройки контекста текущего теста. В случае с WatiN вы можете сделать так, чтобы ваш тест управлял и взаимодействовал с браузером для реализации этого этапа.
На этом этапе я использую WatiN, чтобы открыть Internet Explorer, перейти на страницу Log On сайта, заполнить поля User Name и Password, а затем нажать кнопку Log On. Когда я вновь запускаю тесты, окно Internet Explorer открывается автоматически, и я могу наблюдать, как WatiN взаимодействует с сайтом, «щелкая» ссылки и вводя текст (рис. 7).
Рис. 7. Браузер на автопилоте в WatiN
Этап Given теперь проходит проверку, и я на шаг ближе к реализации функции. Но после этого SpecFlow потерпит неудачу на первом этапе When, так как этот этап пока не реализован. Вы можете реализовать его таким кодом:
[When("I click the \" (.*)\" link")]
public void WhenIClickALinkNamed(string linkName) {
var link = WebBrowser.Link(Find.ByText(linkName));
if (!link.Exists)
Assert.Fail(string.Format(
"Could not find {0} link on the page", linkName));
link.Click();
}
Теперь, когда я вновь запускаю тесты, они терпят неудачу, потому что WatiN не может найти ссылку с текстом «Create New Customer» на странице. Просто добавьте ссылку с этим текстом на основную страницу, и следующий этап успешно пройдет тест.
Вы уже почувствовали систему? SpecFlow поощряет к использованию той де методологии Red-Green-Refactor, которая является основным элементом методов разработки по принципу «сначала тест». Гранулярность каждого этапа в функции выступает в роли виртуальных ограничителей для реализации, стимулируя вас реализовать только ту функциональность, которая необходима для успешного прохождения проверки данного этапа.
А как насчет TDD внутри процесса BDD? К этому моменту я работаю только на уровне страницы и еще должен реализовать функциональность, которая создает запись о клиенте. Ради краткости давайте прямо сейчас реализуем остальные этапы ( рис. 8).
Рис. 8. Остальные этапы в определении этапов
[When(@"I enter the following information")]
public void WhenIEnterTheFollowingInformation(Table table) {
foreach (var tableRow in table.Rows) {
var field = WebBrowser.TextField(
Find.ByName(tableRow["Field"]));
if (!field.Exists)
Assert.Fail(string.Format(
"Could not find {0} field on the page", field));
field.TypeText(tableRow["Value"]);
}
}
[When("I click the \"(.*)\" button")]
public void WhenIClickAButtonWithValue(string buttonValue) {
var button = WebBrowser.Button(Find.ByValue(buttonValue));
if (!button.Exists)
Assert.Fail(string.Format(
"Could not find {0} button on the page", buttonValue));
button.Click();
}
[Then(@"I should see the following details on the screen:")]
public void ThenIShouldSeeTheFollowingDetailsOnTheScreen(
Table table) {
foreach (var tableRow in table.Rows) {
var value = tableRow["Value"];
Assert.IsTrue(WebBrowser.ContainsText(value),
string.Format(
"Could not find text {0} on the page", value));
}
}
Я вновь запускаю тесты, и они теперь заканчиваются неудачей, потому что у меня нет страницы, где можно вводить информацию о клиентах. Чтобы обеспечить создание записей о клиентах, нужна страница Create Customer View. Для создания такого представления в ASP.NET MVC требуется CustomersController. Мне также нужен новый код, а значит, я выхожу из внешнего цикла BDD и попадаю во внутренний цикл TDD, как показано на рис. 2.
Первый шаг — создание неуспешного модульного теста.
Написание тестов модулей для реализации этапов
Создав класс теста CustomerControllersTests в проекте UnitTest, вы должны создать метод теста, который проверяет функциональность, предоставляемую CustomersController. Точнее, вам нужно создать новый экземпляр Controller, вызвать его метод Create и убедиться, что вы получили от него корректные View и Model:
[TestMethod]
public void GetCreateShouldReturnCustomerView() {
var customersController = new CustomersController();
var result = customersController.Create() as ViewResult;
Assert.AreEqual("Create", result.ViewName);
Assert.IsInstanceOfType(
result.ViewData.Model, typeof(Customer));
}
Этот код пока не компилируется, потому что вы не создали CustomersController или его метод Create. Как только вы создадите этот контроллер и пустой метод Create, код будет компилироваться, а тест закончится неудачей, что и есть следующий нужный этап. Написав тело метода Create, вы добьетесь успешного прохождения теста:
public ActionResult Create() {
return View("Create", new Customer());
}
Если вы перезапустите тесты SpecFlow, вы продвинетесь чуть дальше, но ваша Feature все еще не проходит тест. На этот раз тест провалится потому, что у вас нет страницы представления Create.aspx. Если вы добавите ее вместе с нужными полями, как указано в спецификации функции, вы сделаете еще один шаг на своем пути.
Процесс «от внешнего к внутреннему» (outside-in process) для реализации этой функциональности Create выглядит примерно, как показано на рис. 9.
Рис. 9. Процесс «от сценария к модульному тесту»
Зачастую в этом процессе повторяются одни и те же этапы, и со временем ваша скорость их прохождения значительно возрастает, особенно когда вы реализуете вспомогательные этапы (щелчки ссылок и кнопок, заполнение форм и т. д.) в проекте AcceptanceTests и принимаетесь за тестирование ключевой функциональности в каждом сценарии.
Из правильного представления Create ваша Feature теперь будет заполнять соответствующие поля формы и пытаться переслать форму. Вы наверняка догадались, что будет дальше: тест завершится неудачей, поскольку у вас еще нет логики, необходимой для сохранения записи о клиенте.
Следуя тому же процессу, что и раньше, создайте тест, используя код модульного теста с рис. 3. Для компиляции теста добавьте пустой метод Create.После запуска тест провалится.После этого заполните тело метода Create:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Customer customer) {
_repository.Create(customer);
return View("Details", customer);
}
Мой объект Controller является просто контроллером, а само создание записи о клиенте осуществляется объектом Repository, которому известно внутреннее устройство хранилища данных. Я выкинул эту реализацию из статьи для краткости, но здесь важно отметить, что в реальном сценарии необходимость того, чтобы объект Repository сохранял запись о клиенте, должна запускать вложенный цикл модульного тестирования. Если вам нужен доступ к любому объекту, совместно работающему с вашим объектом, и этот объект пока не существует или не имеет требуемой вам функциональности, то вы должны следовать тому же циклу модульного тестирования, что и в случае ваших контроллеров и функции.
После реализации метода Create и создания работающего хранилища вы должны создать представление Details, которое принимает новую запись о клиенте и отображает ее на странице. Затем вы можете запустить SpecFlow еще раз. Наконец, после множества циклов и вложенных циклов TDD вы получаете функцию, которая проходит тесты, а значит, в вашей системе появляется некая проверенная законченная функциональность.
Поздравляю! Вы только что реализовали блок законченной функциональности с приемочным тестом и полным набором модульных тестов, которые будут гарантировать, что новая функциональность продолжит работать и при дальнейшем расширении вашей системы новыми функциями.
Пара слов о рефакторинге
Надеюсь, когда вы создавали тесты уровня модулей в своем проекте UnitTests, вы постоянно осуществляли рефакторинг при каждом создании теста. Двигаясь по цепочке от прохождения модульных тестов к прохождению приемочного теста, вы должны следовать тому же процессу, отмечая возможности для рефакторинга и оптимизации вашей реализации для каждой функции (feature) и всех функций, которые встречаются после нее.
Ищите возможности рефакторинга кода и в проекте AcceptanceTests. Вы обнаружите, что некоторые этапы имеют тенденцию к частому повторению в различных функциях, особенно этапы Given. С помощью SpecFlow эти этапы можно легко поместить в раздельные файлы определения этапов, организованные по функции, например LogInSteps.cs. Тогда ваш основной файл определения этапов останется четким и ориентированным на уникальный сценарий, определяемый вами.
BDD ориентирован на проектирование и разработку. Перенося фокус внимания с объекта на функциональность (функцию), вы получаете возможность проектировать с точки зрения пользователя системы. По мере того как проект функции становится проектом модуля, не забывайте создавать тесты и позаботьтесь о том, чтобы они управлялись дискретными этапами или задачами.
Как и в любой другой дисциплине, обучение применению BDD в вашем рабочем процессе требует некоторого времени. Советую вам попробовать это на практике, используя любые доступные инструменты. При разработке в таком стиле обращайте внимание на вопросы, которые ставит перед вами BDD. Регулярно делайте паузы и ищите способы совершенствования своих практики и процесса, а также обменивайтесь с коллегами идеями по усовершенствованию. Надеюсь, что независимо от используемого вами инструментария освоение BDD принесет вам выигрыш в разработке ПО.
Брэндон Сэтром (Brandon Satrom) — разработчик-идеолог Microsoft в Остине, штат Техас. Ведет блог на userinexperience.com, а также его можно встретить в Twitter под учетной записью @BrandonSatrom.
Выражаю благодарность за рецензирование этой статьи экспертам: Пол Рейнер (Paul Rayner) и Кларк Селл (Clark Sell)