Как использовать юнит-тесты при использовании BDD?

17

Я пытаюсь понять BDD. Я прочитал несколько статей и, как я понял, BDD - это «следующий шаг» от TDD. Я говорю это потому, что считаю, что оба они очень похожи, и, как я мог прочитать в этой статье , BDD родился как улучшение от TDD. Отлично, мне очень нравится идея.

Я подумал, что есть один практический момент: есть файл .feature, в котором БА запишет все ожидаемое поведение системы. Как бакалавр, он понятия не имеет, как строится система, поэтому мы напишем что-то вроде этого:

Сценарий 1: счет в кредит

Учитывая, что счет в кредит

И карта действительна

И диспенсер содержит деньги

Когда клиент просит наличные

Затем убедитесь, что счет списан И убедитесь, что деньги распределяются

И убедитесь, что карта возвращается

Хорошо, это замечательно, но есть много частей системы, которые будут сотрудничать, чтобы это могло произойти (подумайте об объекте Account, объекте Dispenser, объекте Customer и т. Д.). Для меня это выглядит как интеграционный тест.

Я хотел бы иметь модульные тесты. Как проверить код, который проверяет, есть ли у диспенсера деньги? Или что деньги выдаются? Или что счет списывается при необходимости? Как я могу смешать юнит-тесты с тестами "BA Created"?

И.С.Бах
источник
Для этого и используются насмешки и заглушки: для изоляции тестируемых деталей.
Роберт Харви
Извините, я не понимаю. Вы имеете в виду, что я должен издеваться над дозатором? Как бы я это проверить?
JSBach
Когда вы тестируете дозатор, вы издеваетесь над аккаунтом, картой и клиентом.
Роберт Харви
3
Почему вы хотите смешать юнит-тесты и "тесты созданные BA"? Используйте TDD в качестве метода для создания модульных тестов для отдельных частей вашего программного обеспечения и добавьте дополнительные тесты для тестирования требований с точки зрения БА (если хотите, вызовите последние интеграционные тесты). Где вы видите противоречие?
Док Браун
@DocBrown: Под «естественным появлением» я подразумеваю, что некоторые разработчики TDD считают, что программный дизайн естественным образом возникнет из юнит-тестов, когда вы «красно-зеленый-рефакторинг». В The Whiteboard продолжается постоянная беседа по этому вопросу .
Роберт Харви

Ответы:

27

Поведенческая разработка и тестовая разработка являются бесплатными, но не заменяют друг друга.

То, как приложение «ведет себя», описано в Приемочных тестах, которые, согласно BDD, будут характеристиками и сценариями, написанными на Cucumber.

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

Представьте себе процесс сборки автомобиля.

Во-первых, команда разработчиков предлагает свои идеи и в конечном итоге сводит их к сценариям использования:

Scenario: Starting the car
    Given I am standing in front of the drivers door
    When I open the door
    Then the door should lift up DeLorean-style (yeah, baby!)
    When I get into the car
    And turn the key
    Then the engine roars to life

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

Сценарий, приведенный выше, представляет собой тест «Большая картина». Каждый компонент транспортного средства нуждается в тестах «Small Picture», чтобы убедиться, что они функционируют должным образом в целом.

Сборка и тестирование программного обеспечения во многом одинаковы. Вы проектируете сверху вниз, затем строите снизу вверх. Зачем поднимать дверь, если вы даже не можете запустить двигатель? Зачем нужен стартер, если у вас нет батареи?

Ваша команда разработчиков продукта примет приемочные тесты и разработает их в Cucumber. Это дает вам «Большую картину». Теперь инженерная команда должна спроектировать правильные компоненты и то, как они взаимодействуют, а затем протестировать каждый из них отдельно - это ваши модульные тесты.

Как только юнит-тесты пройдут, начните реализовывать сценарии Cucumber. Как только они пройдут, вы получите то, о чем просила команда разработчиков.

Грег Бургхардт
источник
Есть ли способ связать эти тесты "Big Picture" с тестами "Small Picture"? Я имею в виду, когда функции официально меняются (скажем, изменяющийся сценарий огурца), есть ли способ сопоставить это изменение с тестами нижнего уровня (скажем, тесты Junit, предназначенные для этого конкретного сценария огурца)?
Срикант
У вас могут быть вспомогательные методы и пользовательские утверждения, общие для ваших тестов "большой картинки" и "маленькой картинки", но они, скорее всего, будут включать в себя различные настройки для тестирования определенных блоков кода.
Ник МакКарди,
[...] которые в соответствии с BDD будут чертами и сценариями, написанными на огурце. Вы объединяете принципы и инструменты.
jub0bs
Хорошо, хорошо, формулировка немного неправильная, но дело в том, что поведение приложения отражено в функциях и сценариях.
Грег Бургхардт
9

Я пытаюсь понять BDD. Я прочитал несколько статей и, как я понял, BDD - это «следующий шаг» от TDD. Я говорю это потому, что считаю, что оба они очень похожи, и, как я мог прочитать в этой статье, BDD родился как улучшение от TDD.

На самом деле, нет, BDD не является «следующим шагом» от TDD. Это является TDD. Точнее, это перефразирование TDD.

Создатели BDD заметили, что основным препятствием на пути понимания того, что TDD относится не к тестированию, а к поведенческой спецификации, было то, что вся терминология TDD относится к тестированию, а не к поведенческой спецификации. Это все равно, что пытаться не думать о розовом слоне, когда кто-то говорит вам «стараться не думать о розовом слоне», за исключением дополнительного усложнения пребывания в комнате, полной розовых слонов и парня, постоянно кричащего «розовый слон, розовый». слон, "розовый слон" в твоем ухе.

Таким образом, они перефразировали TDD с точки зрения поведенческой спецификации. «Тесты» и «контрольные примеры» теперь являются «примерами», «единицы измерения» - «поведением», «утверждения» - «ожиданиями» и так далее.

Однако методология все та же. Вы начинаете с приемочного теста (я имею в виду «особенность»), увеличиваете масштаб до модульного теста (я имею в виду «пример»), уменьшаете масштаб и т. Д.

Я хотел бы иметь модульные тесты. Как проверить код, который проверяет, есть ли у диспенсера деньги? Или что деньги выдаются? Или что счет списывается при необходимости? Как я могу смешать юнит-тесты с тестами "BA Created"?

Так же, как вы делаете в TDD. Вы можете написать свои функции и свои примеры в разных средах (например, Cucumber и RSpec) или даже на разных языках (например, при написании примеров для проекта C на C и функций в FIT / Fitnesse), вы можете использовать одну платформу функций для обоих ( например, написание примеров и функций в Cucumber), или вы можете использовать единую структуру примеров для обоих (например, написание обоих в RSpec). Вам даже не нужно использовать каркас вообще.

Примером правильно выполненного TDD (который идентичен BDD), использующего только одну платформу, является сам JUnit, который содержит комбинацию модульных тестов (примеров) и функциональных / интеграционных тестов (функций), написанных в самом JUnit.

Я считаю, что Кент Бек называет это «увеличением». Начните с высокого уровня, затем «увеличьте масштаб» до деталей, затем вернитесь обратно.

Йорг Миттаг
источник
1

Отказ от ответственности: я не эксперт в BDD, но я пытаюсь высказать вам свою точку зрения на статью, на которую вы ссылаетесь.

TDD - это метод реализации - сначала вы пишете тест, затем внедряете метод, запускаете тест, выполняете рефакторинг и добавляете дополнительные тесты для того же метода или для нового метода. На самом деле TDD не определяет никаких правил выбора имен классов или методов, это зависит от вас. TDD также не говорит вам «когда вы закончите».

Таким образом, всякий раз, когда вы пишете тест для нового метода, вы должны выбрать имя метода - и это тот момент, когда приходит BDD. Выбирая имена методов, используя бизнес-термины из сценария выше, и выбирая их способом, описывающим поведение вашего класса, вы делаете BDD. Всякий раз, когда вы спрашиваете себя «нужно ли мне добавлять дополнительные тесты», вы можете посмотреть сценарии, предоставленные вашим БА, и проверить, полностью ли вы реализовали все необходимые части. Если нет, вам нужно будет добавить больше тестов.

Автор статьи также предлагает использовать более подходящую схему именования при выборе имен ваших тестов, поэтому он предлагает заменить JUnit инструментом, который не полагается на схему именования, где каждый тестовый пример должен начинаться с название "тест". Хотя я не знаю JBehave, я думаю, что это основное различие между этим инструментом и Junit.

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

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

Док Браун
источник
В качестве быстрого замечания, Junit поддерживает называние ваших тестов чем угодно; вам просто нужно использовать аннотацию @Test. Возможно, это не было сделано еще в 2003 году.
сору
@soru Еще в 2003 году он действительно применил слово «тест».
Лунивор
Автор статьи - Дэн Норт, который в первую очередь придумал концепцию. Одна из вещей, которые он заметил, заключается в том, что слово «тест» заставляет нас перейти к тестированию нашей реализации (область решения), в то время как на самом деле изучение и определение тестов действительно должно держать нас в проблемной области. Дэн назвал BDD «тем, чем должен был быть TDD». Прочитайте это для получения дополнительной информации: dannorth.net/2012/05/31/bdd-is-like-tdd-if
Lunivore