5й подкаст Петербургской группы ALT.NET

SOLID & TDD и прочие показатели качества кода

Ведущие: dnesteruk & butaji

Наши гости: Alexander Byndyu и Vitaly Stakhov

SCRUM & XP

OOD: Best practicies

SOLID

  • Single Responsibility Principle
  • Open/Closed Principles
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

TDD: Best Practicies

Ещё говорили о

Pain-Driven Development

Spolsky vs Uncle Bob

NHibernate Sources, NAnt

 

Подкасты Петерубргской Группы Alt.Net

Подкасты Петерубргской Группы Alt.Net

Подкасты о разработке в среде .Net. Ключевые слова: C#, F#, Boo, Visual Studio, .Net, PostSharp, Asp.Net личная подкаст-лента Петербургская Группа Alt.NetПетербургская Группа Alt.Net (подробнее, RSS-поток)


4й подкаст Петербургской группы ALT.NET

Всё, что вы хотели узнать о ASP.NET

Участники: dnesteruk & butaji

Что нового в ASP.NET MVC2.

  • Асинхронные контроллеры
  • Зоны (areas)
  • Валидация через data annotation
  • Строго-типизированные хелперы
  • Хелпер-темплейты, параметры по-умолчанию

Альтернативные view engines

Удобен ли Visual Studio для веб-разработки

FubuMVC

  • Новое понимание MVC. Другой контроллер. Конвенции.

Почему я уйду на Ruby on Rails / Django

Как хорошо работать с Asp.Net AJAX и jQuery

HTML5 + CSS3 (@font-face)

RIA

Создавать ли View для iPhone

Подкасты Петерубргской Группы Alt.Net

Подкасты Петерубргской Группы Alt.Net

Подкасты о разработке в среде .Net. Ключевые слова: C#, F#, Boo, Visual Studio, .Net, PostSharp, Asp.Net
личная подкаст-лента Петербургская Группа Alt.NetПетербургская Группа Alt.Net (подробнееRSS-поток)


Альтернативный MVC Framework на ASP.NET: FubuMVC

Введение

Почему же альтернативный? Всё просто, данный framework пишется силами выдающихся участников ALT.NET community, а именно:

Jeremy Miller, Chad Myers, Mark Nijhof, Ryan Kelley, и Joshua Flanagan.

FubuMVC не имеет никакого отношения к ASP.NET MVC Framework, кроме того, что так же построен поверх ASP.NET и реализует паттерн Front-Controller. Название FubuMVC строится из акронима “For us by us” и аббривеатуры MVC (кто ещё не знает, что это значит Model-View-Controller ?). Проект был инициирован по причине недовольства вышеперечисленных личностей архитектурными решениями, принятыми в ASP.NET MVC. Сказать, по правде, по прошествии года, после старта проекта, он не утратил своей элегантности и простоты в подходах.

FubuMVC вносит несколько непривычное понимание Controller’а. Теперь это не просто некоторый класс, теперь это больше логическая связность некоторых методов. Это раскрывает более широкие возможности для настройки специфичного поведения Controller’а, к примеру, обработки ошибок, реализации правил кэширования, определения типа возвращаемых значений. К тому же возможность динамического объединения вызовов Action’ов уже является удобным механизмом к расширению. Далее мы более подробно поговорим об особенностях этой реализации в FubuMVC.

В качестве View Engine (в данном случае является лишь определением и не имеет отношения к ASP.NET MVC View Engine) используется механизм рендринга WebForms (проще говоря FubuPage, которая является View в FubuMVC, наследует от System.Web.UI.Page), но имеется возможность в подключении всех существующих в ASP.NET MVC ViewEngine’ов, примером тому может быть реализация SparkViewEngine.

Конечно же уместным будет вопрос, а зачем же нужен “другой” MVC Framework, с меньшим количеством участников проекта, с меньшим вниманием со стороны разработчиков, с меньшим количеством тестеров и прочими атрибутами mainstream проектов.

В основу проекта FubuMVC его создатели заложили больше возможностей для кастомизации проекта под прикладные нужды, а так же конвенциям (соглашениям) относительно настройки и расширяемости. Причём конвенции должны покрывать основные и типичные нужды приложения, коих в разработки решений достаточно большое количество. Какие-либо дополнительные разработки будут инициировать собой появление дополнительных модулей.

ScreencastsАналогичные конвенции (соглашения) существую в известном всем MVC Framework на Ruby: Ruby On Rails. На своей практике разработки под Ruby On Rails я неоднократно убеждался, что данные конвенции действительно позволяют снизить сложность и количество написанного кода. Примером тому может служить ORM Active Record с его соглашениями касательно преобразования объектов в таблицы реляционной базы данных, а так же соглашение, относительно хранения конфигурации в формате YAML.

Официальный сайт проекта: http://fubumvc.com/

FubuMVC на GitHub: http://github.com/darthfubumvc/fubumvc

Первое погружение

Начнём с конвенций именования и структуры проекта. Вся работа с настройкой приложения FubuMVC ведётся через некоторый DSL, стиль конфигурирования очень близок к работе с FluentNhibernate.

public class HelloWorldFubuRegistry : FubuRegistry
{
    public HelloWorldFubuRegistry()
    {
        IncludeDiagnostics(true);

        Applies.ToThisAssembly();

        Actions
            .IncludeTypesNamed(x => x.EndsWith("Controller"));

        Routes
            .IgnoreControllerNamespaceEntirely()
            .ConstrainToHttpMethod(action => action.Method.Name.EndsWith("Command"), "POST")
            .ConstrainToHttpMethod(action => action.Method.Name.StartsWith("Query"), "GET");

        Views
            .TryToAttach(x=>
            {
                x.to_spark_view_by_action_namespace_and_name(GetType().Namespace);
                x.by_ViewModel_and_Namespace_and_MethodName();
                x.by_ViewModel_and_Namespace();
                x.by_ViewModel();
            });

        Output.ToJson.WhenCallMatches(action => action.Returns<AjaxResponse>());

        HomeIs<HomeInputModel>();
    }
}

Исходя из данной конфигурации IoC-container’а нетрудно догадаться о следующем:

  • Все классы, оканчивающиеся на “Controller” будут зарегистрированны в качестве Controller
  • Все запросы, оканчивающиеся на “Command” должны будут приниматься POST’ом, а начинающиеся на “Query” GET’ом
  • Все View будут заполняться соответствующими по именованию ViewModel
  • Весь вывод, возвращающий тип AjaxResponse будет серилизоваться в JSON

В качестве IoC-container’а в FubuMVC выбран StructureMap. Выбор не случаен, т.к. фактически StructureMap является старейшим IoC/DI-container’ом. Начало разработки датировано июнем 2004ого года и велось Jeremy D. Miller, так же и участником проекта FubuMVC.

Второе погружение

Давайте рассмотрим несколько примеров приложений на FubuMVC

Первое из них http://github.com/DarthFubuMVC/fubumvc-examples/tree/master/src/Actions/ControllerActionStyle/

Начнём, с того, что проверим его работоспособность:

image

В namespace’е SimpleWebsite.Core определена наша модель предметной области, а именно Movies, работе с которыми и просвещенно приложение.

В SimpleWebsite.Controllers определен единственный Controller и View, работу которых мы и видим на рисунке выше.

Давайте разберемся с MoviesController. Судя по его конструктору нетрудно догадаться, что DependencyInjection мы получаем out-of-box без каких-либо переопределений Controller Factory:


private readonly IRepository _repository;

public MoviesController(IRepository repository)
{
    _repository = repository;
}

Метод List() является “списочным” и предоставляет нам доступ к ViewModel


public ListMoviesViewModel List()
{
    return new ListMoviesViewModel {Movies = _repository.Query<Movie>()};
}

Стоит обратить внимание на конвенцию именования в данном случае. Под ViewModel (читается так же как PresentationModel) понимается адаптированная для представления модель, что подчеркивает SoC в реализации FubuMVC. View в данном случае будет строго типизировано на  этот тип:

 public class List : FubuPage&lt;ListMoviesViewModel&gt;   <br />{}

Метод Add() попадает под правило обработки AjaxResponse, следовательно вернется на страницу в виде JSON, где будет радужно встречен jQuery обработчиком.

image

Аналогичная ситуация с методом Remove().

Стоит обратить внимание на конвенцию именования принимаемых данными методами типов:

AddMovieInput, RemoveMovieInput

Наименования данных классов указывают на направление данных, т.е. их ввод с запросом. С помощью этих типов на View мы определяем Url для обработки соответствующих Action’ов Controller’а:

<%= Get<IUrlRegistry>().UrlFor(new AddMovieInput()) %>

FubuMVC реализует 3 модели обработки запросов:

  1. Controller / Action Привычный для ASP.NET MVC Framework способ. Определяется некоторый тип — Controller, который содержит в себе соответствующие методы — Action’ы. Данный пример был рассмотрен выше.
  2. Controller-less Actions (HandlerStyle) Данный способ подразумевает под собой “обезличенные” Action’ы. т.е. без привязки к какому-либо Controller’у. Правила нахождения Action’ов описываются Policy, которые можно описывать и добавлять в коде.
  3. REST-like (EndPointStyle) Этот способ близок к предыдущему, однако, в отличии от него реализует не только метод Execute, а все методы, необходимые для REST взаимодействия, каждый метод Get(), Post(), Put(), Head() в дальнейшем будет соответствовать типу HTTP запроса:
var httpVerbs = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
    {"GET", "POST", "PUT", "HEAD"};

Погружаемся далее

Как вы уже догадались, FubuMVC славится своими возможностями для расширения. Предлагаю ознакомиться с ещё одним примером: http://github.com/DarthFubuMVC/fubumvc-examples/tree/7c4b2165aedb6754a01538aee956e29d4060654c/src/Outputs/VaryByAcceptHeader

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

Этот пример практически ни чем не отличается от рассматриваемого, раннее, за тем лишь исключением, что в классе

VariableOutputConvention : IConfigurationAction

мы регистрируем интересующие нас возвращаемые типы, а так же указываем дополнительный Behavior для рендринга страницы:

RenderVariableOutput : BasicBehavior

После чего достаточно только заполнить интересные вам Movies http://localhost:59187/movies/list и попросить вернуть их в JSON http://localhost:59187/movies/list?renderformat=json или в XML http://localhost:59187/movies/list?renderformat=xml

Данный пример наглядно иллюстрирует точки расширения FubuMVC для любых нужд.

Диагностика

По адресу http://localhost:59187/_fubu вас будет ждать небольшой сюрприз, а именно – диагностическая утилита для FubuMVC.image

C её помощью вы сможете просматривать все зарегистрированные в вашем приложении

  • Chains – цепочки поведения, так называются логические связи между маршрутами и Action’ами. О цепочках можно посмотреть все обертки и возвращаемые значения.
  • Routes – показывает все зарегистрированные маршруты, и связанные с ними Action’ы, тип выводимых данных и цепочки поведения.
  • Actions – зарегестрированные в приложении Action’ы, их маршруты и возвращаемые значения
  • Inputs – возможные типы и способы ввода в вашем приложении со стороны запросов

Заключение

При первом и поверхностном знакомстве проект FubuMVC не показался мне чем-то выдающимся. Однако в последнее время мой интерес к нему постоянно растёт. Я считаю, что FubuMVC является более удобным и гибким инструментом, по сравнению с ASP.NET MVC. Однако это ещё не значит, что я уже готов доверить данному проекту свои коммерческие проекты. Тот факт, что сообщество всё же поддерживает многообразие качественных решений для создания приложений на ASP.NET, может только радовать.

Материалы

FubuMVC Contrib http://code.google.com/p/fubumvc-contrib/

Front Controller http://msdn.microsoft.com/en-us/library/ms978723.aspx

FubuMVC — Front Controller style framework  http://blog.fohjin.com/blog/2009/2/21/FubuMVC_Front_Controller_style_framework

FubuMVC Google Group http://groups.google.com/group/fubumvc-devel?pli=1

Ещё один MVC Framework на ASP.NET OpenRasta http://trac.caffeine-it.com/openrasta

Соглашение относительно настройки http://msdn.microsoft.com/ru-ru/magazine/dd419655.aspx


3й подкаст Петербургской группы Alt.Net

Литература для .Net-разработчика

Участники: dnesteruk & butaji

Non-.Net

Domain-specific books:

Подкасты Петерубргской Группы Alt.Net

Подкасты Петерубргской Группы Alt.Net

Подкасты о разработке в среде .Net. Ключевые слова: C#, F#, Boo, Visual Studio, .Net, PostSharp, Asp.Net
личная подкаст-лента Петербургская Группа Alt.NetПетербургская Группа Alt.Net (подробнееRSS-поток)


Каких возможностей мне не хватает в SharePoint 2010 BCS

В данной заметке я решил немного поразмышлять о том, чего же мне не хватает в BCS при планировании основных сервисов приложений, руководствуясь стандартными для SharePoint практиками. Большинство из этих ограничений связаны с природой сервисов BCS, а именно тем, что данные не находятся в локальном хранилище, соответственно не могут полностью контролироваться с помощью сервисов SharePoint.

Итак, начнём:

  • Нельзя давать разрешения на отдельные записи во внешнем списке (external list). Наконец-то SharePoint в исполнении 2010ой версии научили корректно использовать Access Control Lists (ACL), однако, по вполне понятным причинам данные возможности не доступны при работе с внешними данными
  • Возможности рабочих процессов не доступны полностью для внешних списков. Казалось бы, всё замечательно и готово для интеграции, однако внешние данные остаются внешними данными, и многие события, необходимые для работы с рабочими процессами недоступны для SharePoint, однако это не исключает использование внешних данных в рабочих процессах, работающих на обычных списках. Об этой проблеме и способах её разрешения довольно-таки подробно описано в статье Using SharePoint workflows with Business Connectivity Services (BCS).
  • Отсутствие версионности и истории изменений во внешних списках. Вполне логично, что внешние списки остаются лишь “обёрткой” для внешних данных и хранить изменения, а следовательно и обеспечивать версионность, довольно-таки неординарная задача, которую команда BCS решила не касаться, по той же причине “элементы социального взаимодействия”, такие как рейтинги и тегирование, так же будут недоступными при работе с внешними данными (BCS).
  • Экспорт в Excel. Очень странно почему данный функционал не доступен, т.к. не накладывает никаких ограничений на используемые данные, а просто меняет их представление. Как альтернативу данному подходу могу предложить что-нибудь наподобие Print List (http://www.sharepoint-tips.com/2007/01/how-to-add-print-list-option-to-list.html), т.е. решения по экспорту внешних данных из SharePoint будут подразумевать кастомизацию.
  • RSS каналы. С одной стороны причины схожи с экспортом в Excel, однако здесь, как мне кажется, противоречие даже со здравым смыслом, т.е. RSS-канал как правило должен отслеживать изменения в данных и оповещать об этом подписчика, в случае с внешними данными, они могут и не меняться, а будет меняться лишь выборка, что будет генерировать многочисленное количество неконтролируемых обновлений.
  • Просмотр в виде таблицы. Очень удобная функция, не понятно, что именно сподвигло на её отсутствие команду разработчиков, скорее всего возможности пакетной обработки в новом интерфейсе SharePoint, которыми она была так удобна.
  • Внешние данные не доступны для доступа через REST сервисы. Как мне кажется причина так же в возможности непрогнозируемого изменения данных произвольным образом, что не даёт никакой гарантии для потребителя данных сервисов.

В заключение

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


Полноценный Behavior Driven Development на .NET

Введение

Меня переполняют эмоции. Это связанно с тем, что сегодня мой товарищ сообщил о следующем: есть полноценная реализация BDD движка для .NET.

Называется проект SpecFlow

Исходный код ныне базируется на GitHub http://github.com/techtalk/SpecFlow

Немного теории

Вопрос о том, что же такое Behavior Driven Development неоднозначен. Особенно противоречивы его отношения с Test Driven Development. Однако предлагаю абстрагироваться от сравнения двух подходов и договорится, что суть этого есть одно и тоже, т.к. особенных различий нет. Основной чертой выделяющей BDD от TDD по-моему усмотрению является ориентация на различных участников процесса производства программного обеспечения, будь то менеджер, разработчик, тестер, заказчик. Вы вместе пишете тесты, и вместе можете развивать проект в нужном направлении и вполне понятных терминах. Так же на ум в данном случае приходит такой термин, как Ubiquitous Language из Domain Driven Design. А ведь и в самом деле, обобщение терминологии описания вашей предметной области вполне может ложится на практику BDD.

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

Все известные инструменты (к примеру mock-объекты) и практики (такие как шаблоны тестирования), используемые вами при разработке в стиле TDD, изменятся незначительно при переходе на BDD стиль, в связи с чем можно начать применять BDD уже сегодня. Так же вполне возможно, что вам необходимо будет произвести более низкоуровневое тестирование некоторых компонентов, что несомненно приведёт к смешиванию двух практик, что несомненно должно происходить осознано и с должен вниманием.

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

Инструменты

cuke_logo[1] На данный момент существует множество BDD framework’ов, однако “наиболее верным” с точки зрения родоначальников данного термина (Dan North, David Chelimsky, Aslak Hellesøy) является такой проект как: Cucumber (ранее известный как RSpec). Этот проект написан для Ruby. Большинство RubyOnRails разработчиков (как основные представители ruby сообщества) пользуются именно этим фреймворком для тестирования своих продуктов.

Известны некоторые способы запуска данного проекта под .NET с помощью IronRuby, однако должной поддержки со стороны как сред разработки в .NET, так и внимания сообщества такое решение не получило.

Инструменты для .NET в основном копируют формат и принципы, заложенные в Cucumber, их существует несколько:

  • SpecFlow – предмет сегодняшнего разговора (из плюсов – аналогия с Cucumber и интеграция в Visual Studio 2008 и 2010)
  • NBehave – работа с данным фреймворком близка к возможностям Cucumber в настоящее время (до этого он так же был в разряде “многословных” и  это, наверное, наиболее распространенный BDD фреймворк среди .NET разработчиков)
  • NSpecify, NSpec – довольно-таки “многословные” фреймворки для BDD
  • Specter – аналогично, примечателен тем, что написан на Boo

Теперь практика

Для того, чтобы проиграться с этим замечательным инструментом нам понадобятся:

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

Создавать мы с вами будет стандартный пример для подобного рода фреймвороков, а именно Калькулятор.image

Создадим новый solution в студии, в котором будет два проекта.

  1. Calculator
  2. Calculator.Tests

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

  • добавить reference на TechTalk.SpecFlow.dll (которая скорее всего окажется в папке с установленным SpecFlow)
  • добавить reference на nunit.framework.dll (его следует искать в GAC’е)

Теперь всё готово для того, чтобы погрузиться в мир BDD. Откиньтесь на спинки кресел и расстегните ремни.

В пункте Add New Item у вас наверняка появились новые пункты, начинающиеся на SpecFlowimage

Далее задайте имя нашей фиче addition.feature и щелкните Add.

Как вы догадались мы добавим описание первой фичи, для этого тот текст, который будет содержаться в файле по-умолчанию следует заменить на следующий:

http://github.com/aslakhellesoy/cucumber/blob/master/examples/i18n/en/features/addition.feature# language: en

Feature: Addition

  In order to avoid silly mistakes

  As a math idiot 

  I want to be told the sum of two numbers

  Scenario Outline: Add two numbers

    Given I have entered <input_1> into the calculator

    And I have entered <input_2> into the calculator

    When I press <button>

    Then the result should be <output> on the screen

  Examples:

    | input_1 | input_2 | button | output |

    | 20      | 30      | add    | 50     |

    | 2       | 5       | add    | 7      |

    | 0       | 40      | add    | 40     |

Жмём ctrl+s и большая часть работы по описанию выполнена.

Теперь нам надо сделать описание steps, для того, чтобы связать сценарий с тестируемым модулем. Для этого добавьте новый элемент SpecFlow Step Definition, назовём мы его calculator_steps.cs.

Данный файл уже содержит в себе некоторые записи по-умолчанию, в принципе они вполне подходят для нашего примера. (Кстати, обратите внимание как строго упорядочены все методы по шаблону AAA: Arrange, Act, Assert, в данной интерпретации Given, When, Then)

Однако немного их всё же придется изменить.

Внутри данного метода:

[Given("I have entered (.*) into the calculator")]
public void GivenIHaveEnteredSomethingIntoTheCalculator(int number)
{
  //TODO: implement arrange (recondition) logic
  // For storing and retrieving scenario-specific data,
  // the instance fields of the class or the
  //     ScenarioContext.Current
  // collection can be used.
  // To use the multiline text or the table argument of the scenario,
  // additional string/Table parameters can be defined on the step definition
  // method.

  ScenarioContext.Current.Pending();
}

Мы видим, что на нашем калькуляторе печатают некоторые числа, ок, подтвердим это:

[Given("I have entered (.*) into the calculator")]
public void GivenIHaveEnteredSomethingIntoTheCalculator(int number)
{
    Calculator.Input(number);

}

И не стесняйтесь того, что пока Visual Studio не совсем понимает, что такое Calculator 😉

Отлично, смотрим на следующий метод, его мы тоже немного поправим:

[When("I press add")]
public void WhenIPressAdd()
{

    Calculator.Add();

}

И, вслед за ним, удостоверимся, что получаем именно то, чего желаем:

[Then("the result should be (.*) on the screen")]
public void ThenTheResultShouldBe(int result)
{
    Assert.IsEqual(result, Calculator.Result);
}

Теперь самое время разобраться с нашим калькулятором.

Создадим следующее поле:

protected Calculator Calculator = new Calculator();

Теперь пора бы разобраться и с типом Calculator, его мы создадим в проекте Calculator. Так же добавим reference из проекта Calculator.Tests на проект Calculator. С типом так же всё в порядке, однако не хватает некоторых методов, их тоже следует создать.

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

image

Теперь можно заняться имплементацией нашего калькулятора. На данный момент я предлагаю следующее:

public class Calculator
{
  private IList<int> _buffer = new List<int>();

  public int Result { get; private set; }

  public void Input(int number)
  {
    _buffer.Add(number);
  }

  public void Add()
  {
    Result = _buffer.Sum();
    _buffer.Clear();
  }

}

Запускаем наши тесты и видим, что они проходят, супер!

image

Вроде бы с первой фичей мы успешно разобрались, почему бы не взяться за вторую?

Второй возможностью будет деление:

http://github.com/aslakhellesoy/cucumber/blob/master/examples/i18n/en/features/division.feature

# language: en

Feature: Division

  In order to avoid silly mistakes

  Cashiers must be able to calculate a fraction

  Scenario: Regular numbers

    Given I have entered 3 into the calculator

    And I have entered 2 into the calculator

    When I press divide

    Then the result should be 1.5 on the screen

*в оригинале для cucumber у aslakhellesoy несколько иной синтаксис, но он на данный момент не поддерживается в SpecFlow

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

[When("I press divide")]
public void WhenIPressDevide()
{
  Calculator.Devide();
}

Добавить так же метод в класс Calculator.

Скомпилировать наш проект. И запустить тесты. Конечно же они не пройдут, т.к. деление мы с вами ещё не реализовали:

public void Devide()
{
  Result = _buffer[0] / _buffer[1];
  _buffer.Clear();
}

После этого мы запускаем тесты с надеждой на зеленную полосу, однако этого не происходит, т.к. мы указали тип int во всех методах, однако же в описании последней фичи мы ожидаем дробное число. Необходимо отрефакторить проект в связи с новыми потребностями. После всех изменений тесты проходят на ура и мы получаем калькулятор с возможностью деления и сложения, описанных строго в бизнесс-требованиях.

Материалы

Исходный код рассматриваемого проекта http://dl.dropbox.com/u/4070949/Calculator.zip

Скринкаст от создателей SpecFlow http://www.specflow.org/specflow/screencast.aspx

Моя статья Пример практики BDD при работе со Specter Framework

Книга The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends

Википедия http://en.wikipedia.org/wiki/Behavior_Driven_Development


Spb ALT.NET Podcast #2: Persistence in .NET

Участники: butaji & dnesteruk

Persistence в .Net-приложениях

Подкасты Петерубргской Группы Alt.Net

Подкасты Петерубргской Группы Alt.Net

Подкасты о разработке в среде .Net. Ключевые слова: C#, F#, Boo, Visual Studio, .Net, PostSharp, Asp.Net

личная подкаст-лента Петербургская Группа Alt.NetПетербургская Группа Alt.Net (подробнееRSS-поток)