Статьи

Acceptance Test Driven Development

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

Если предыдущая статья была теоретической, давайте теперь рассмотрим использование приемочного тестирования в качестве практики в нашем процессе разработки. Я предпочитаю использовать Acceptance Test Driven Development или ATDD.

В двух словах

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

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

[Обратите внимание, что я сознательно решил не использовать слово готово , поскольку после реализации этой функции нам часто нужно немного поиграться с пользовательским интерфейсом.]

Пример задачи

Для примера, мы собираемся построить корзину покупок для книжного ката о Гарри Поттере, используя ATDD. Клиенты получают скидку в зависимости от количества книг в серии, которую они покупают. Это упражнение взято из списка ката с сайта Coding Dojo. Для полного описания вы можете прочитать: http://codingdojo.org/cgi-bin/wiki.pl?KataPotter .

Первые 5 книг из серии «Гарри Поттер» уже в продаже. Один экземпляр любой из книг стоит 8 долларов. Если вы покупаете две разные книги из серии, вы получаете скидку 5%, если вы покупаете три разные книги, вы получаете скидку 10%, если вы покупаете 4 разные книги, ваша скидка составляет 20%, а если вы покупаете все 5, вы получаете 25% скидка.

Давайте создадим пару и создадим эту функцию вместе.

Обсудить и дистиллировать

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

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

я II III IV В формула $
1 1 * 8 8,00
1 1 2 * 8 * 0,95 15,20
1 1 1 3 * 8 * 0,9 21,60
1 1 1 1 4 * 8 * 0,8 25,60
1 1 1 1 1 5 * 8 * 0,75 30,00
2 2 * 8 16,00
2 1 2 * 8 * 0,95 + 1 * 8 23,20
2 2 2 1 1 4 * 8 * 0,8 + 4 * 8 * 0,8 51,20

Большинство из этих строк говорят сами за себя. Последняя строка показывает, что есть 2 комплекта из 4 книг. Это может быть удивительно, потому что вы ожидаете набор из 5 книг плюс набор из 3 книг. Причина этого заключается в том, что скидка должна быть оптимизирована для покупателя. Наилучшая возможная скидка в этом сценарии — приобрести 2 комплекта из 4 книг, что на 0,40 доллара дешевле, чем комплект из 5 книг и комплект из 3 книг.

После собрания мы отстраняем приемочные тесты от этих примеров и сохраняем их как сценарии Cucumber. Сценарий для первого примера гласит:

1
2
3
4
Scenario: buy single book without discount
 
  When I buy 1 copy of "Harry Potter I"
  Then I must pay $8

Сценарий для второго примера очень похож на первый:

1
2
3
4
Scenario: buy two distinct books
 
  When I buy 1 copy of "Harry Potter II"
  Then I must pay $15.20

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Scenario Outline: buy discounted Harry Potter books
 
  When I buy <I> copies of "Harry Potter I"
  And I buy <II> copies of "Harry Potter II"
  And I buy <III> copies of "Harry Potter III"
  And I buy <IV> copies of "Harry Potter IV"
  And I buy <V> copies of "Harry Potter V"
  Then I must pay $<Total>
 
Examples:
  | I | II | III | IV | V | Total |
  | 1 | 0  | 0   | 0  | 0 8.00 |
  | 1 | 1  | 0   | 0  | 0 | 15.20 |
  | 1 | 1  | 1   | 0  | 0 | 21.60 |
  | 1 | 1  | 1   | 1  | 0 | 25.60 |
  | 1 | 1  | 1   | 1  | 1 | 30.00 |
  | 2 | 0  | 0   | 0  | 0 | 16.00 |
  | 2 | 1  | 0   | 0  | 0 | 23.20 |
  | 2 | 2  | 2   | 1  | 1 | 51.20 |

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

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

Теперь наша команда готова к этапу внедрения.

Осуществлять

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

Пример такой сгенерированной функции для Java приведен ниже. Это связующий код для одного шага в сценарии с огурцом, также известный как определение шага.

1
2
3
4
5
When("^I buy (\\d+) copies of \"([^\"]*)\"$")
public void I_buy_copies_of(int arg1, String arg2) throws Throwable {
    // Express the Regexp above with the code you wish you had
    throw new PendingException();
}

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

Когда первый сценарий завершается ошибкой с сообщением, описывающим отсутствующую функцию, мы реализуем эту функцию. Затем мы переходим к следующему и так далее, пока все функции не пройдут. Мы сохраняем наш код в чистоте, используя TDD.

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

Рассмотрение

Последним этапом создания новой функции является ее рассмотрение. Я не говорю об обзорах кода здесь, они происходят на этапе реализации.

Чтобы завершить нашу новую функцию, мы проведем предварительное тестирование. Исследовательское тестирование — это выяснение того, как на самом деле работает система, используя ее вольный стиль. Т.е. нет тестовых скриптов для подражания. Вместо этого тестовые случаи изобретаются на лету и сразу выполняются против системы. Если вы хотите узнать больше о предварительном тестировании, я могу порекомендовать вам прочитать Элизабет Хендрикс в ее фантастической книге « Исследуй это!».

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

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

Больше примеров

Лично я считаю ATDD очень приятным способом работы всей команды. Обладая преимуществами четких требований, вам нравится тот факт, что вы создаете автоматизированный набор регрессий, который вы можете (и должны) запускать каждую сборку. Этот набор регрессии дает команде большую уверенность, чтобы не бояться вносить изменения в любом месте. Как только что-то сломается, тест не пройден, и команда знает, что исправить.

Если вам нравится видеть больше примеров ATDD, вам следует прочитать ATDD by Example , в котором Маркус Гертнер соединяется с вами, чтобы практиковать ATDD во время работы с примерами проблем.

Ссылка: Приемочное тестирование по разработке от нашего партнера JCG Барта Баккера в блоге Software Craft .