Pull to refresh

BDD с помощью Cucumber

Ruby *
Если вы привыкли сначала писать код, а потом его тестировать, то с BDD такой подход совсем не уместен. Сила BDD в том, что он помогает вести разработку начиная со стадии оформления ТЗ. Для BDD это список свойств (фич), который уместно писать вместе с заказчиком.

Но самое главное, что по этому же списку происходит автоматическое тестирование проекта. Инструмент тестирования (в нашем случае это Cucumber) методично пройдет по вашему перечню и дотошно проверит реализацию каждой фичи.

Разработка с использованием Cucumber состоит из 3-х основных этапов.
  1. Описание фич проекта простым человеческим языком. И даже необязательно английским.
  2. Определение поступков (step definition) на Ruby
  3. Цикл разработки: проверка фич кукумбером и реализация не прошедших тестирование фич ручками.


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

1-й этап. Фичи.



Список

Например, мы, как всегда, разрабатываем новый blog. Вот и запишем свойства нашего блога в файл ./features/blog.features. Для каждого свойства опишем также понятия Зачем, Кто и Что (In order, A, Should). Это пожелания BDD, на самом деле на результат они не влияют, но зато помогают нам самим более четко сформулировать чего-же мы хотите от этой фичи.

Feature: Post articles

  In order to show trip photos
  A owner
  Should be abble to post article

Feature: Make comments

  In order to contact
  A user
  Should be abble to make comments


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

Сценарии


Свойство имеет одно или несколько сценариев поведения. Именно по этим сценарием и происходит тестирование. Каждый сценарий описывается тремя категориями: Условие (Given), Событие (When), Результат (Then). Если у вас несколько условий, событий или результатов, то дополнительные прописывается через And/But.

Feature: Post articles

  In order to show trip photos
  A owner
  Should be abble to post article
 
  Scenario: Post article by owner

    Given I signed up as owner
    When I write article "About my last nigh trip"
    And text of article is "It was very hard night.."
    And I post article
    Then I should see "Article is created"

  Scenario: Post article by user

    Given I signed up as user
    When I write article "My fantazy"
    And text of article is "..no more"
    And I post article
    Then I should see "You have no access to post articles"


На этом этапе мы уже имеем понятный человеку и инструменту тестирования список фич. И уже сейчас можно запускать:

> cucumber features/blog.features

...

2 scenarios (2 undefined)
12 steps (12 undefined)
0m0.012s

You can implement step definitions for undefined steps with these snippets:

Given /^I signed up as owner$/ do
  pending
end

When /^I write article "([^\"]*)"$/ do |arg1|
  pending
end

When /^text of article is "([^\"]*)"$/ do |arg1|
  pending
end

When /^I post article$/ do
  pending
end

Then /^I should see "([^\"]*)"$/ do |arg1|
  pending
end


Cucumber подсказывает что делать дальше, какие поступки нам необходимо определить (step definition).

Этап 2. Определение поступков (step definition)



Копируем подсказку cucumber-а в /features/step_definitions/blog_steps.rb и прописываем поступки, например:

    Given /^I signed up as (.*)$/ do |role|
       current_user=User.find_by_role(role)
    end

    When /^I write article "([^\"]*)"$/ do |arg1|
        aricle=Article.create(:subject=>arg1,:user=>user)
        same_subject=subject
    end

    When /^text of article is "([^\"]*)"$/ do |arg1|
      aricle.text=arg1
    end

    When /^I post article$/ do
      artricle.save!
    end

    Then /^I should see "([^\"]*)"$/ do |arg1|
       response.should contain(arg1)
    end


Теперь у нас готов и список фич и определено их поведение.

Этап 3. Тестирование и разработка



Запускаем тест:

> cucumber  features/blog.features

Feature: Post articles
  In order to show trip photos
  A owner
  Should be abble to post article

  Scenario: Post article by owner                                              # features/blog.features:6
    Given I signed up as owner                                                 # features/step_definitions/blog_steps.rb:1
      uninitialized constant User (NameError)
      features/blog.features:7:in `Given I signed up as owner'
    When I write article "About my last nigh trip"                             # features/step_de


Как видно, cucumber сообщил о том, что не знает ни о каком User. В таком случае создаем код модели User.

Опять запускаем Cucumber. На этот наз он ругается о другой ошибке — реализуем еще код дабы исправить ее и т.д. до тех пор.

Когда у cucumber пройдут все тесты — весь код будет реализован. Таким образом мы закончили 3-й этап и можно переходить к дальнейшему дизайну приложения и реализации новых фич.

Если интересно, в следующий раз расскажу и покажу как разрабатывается реальное приложение с Cucumber, Shoulda и волшебником webrat.

PS



Материалы:

cukes.info — Сайт cucumber
nlp.od.ua/behavoir-driven-development — На русском о BDD
railscasts.com/episodes/155-beginning-with-cucumber — screencast Cucumber для начинающих
github.com/thoughtbot/clearance/tree/master — Clearance имеет отличный пример использования cucumber-а
Tags:
Hubs:
Total votes 34: ↑30 and ↓4 +26
Views 101K
Comments Comments 21