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

  1. Главная
  2. Блог
  3. Автоматизация тестирования

Автоматизация тестирования

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

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

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

Главное

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

Дебаты TDD против BDD часто оформляются как выбор стороны. На самом деле они отвечают на разные вопросы. Разработка, основанная на тестировании, спрашивает, выполняет ли код то, что задумал разработчик, а разработка, основанная на поведении, спрашивает, согласна ли команда с тем, что программное обеспечение вообще должно делать.

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

Короткий ответ

Разработка через тестирование (TDD) — это практика кодирования. Вы пишете небольшой провальный тест, выполняете его с помощью простейшего кода, а затем улучшаете дизайн. Тесты пишутся в коде, и в основном разработчиками. Кент Бек популяризировал эту практику.

Разработка на основе поведения (BDD) — это практика совместной работы, выросшая из TDD, и этот термин ввел Дэн Норт. Разработчики, тестировщики и бизнесмены согласовывают примеры того, как должна вести себя система, написанные простым языком, и эти примеры затем можно автоматизировать.

TDD против BDD бок о бок

Аспект ТДД БДД
Основное внимание Правильный, хорошо продуманный код Общее понимание поведения
Написано в Язык программирования Простой язык, например Gherkin
Написал Разработчики Бизнес, контроль качества и разработчики вместе
Читается Разработчики Все в команде
Типичный уровень Единица Особенность или принятие
Начальная точка Неудачный тест Разговор с примерами
Цикл Красный, зеленый, рефакторинг Открывайте, формулируйте, автоматизируйте
Общие инструменты pytest, JUnit, Jest Огурец, поведение, SpecFlow, Reqnroll

Особенность

Вот бизнес-правило, которое мы реализуем: При заказе 1000 и более скидка 10%. Участники получают дополнительную скидку 5 % на эти заказы.

Это может показаться ясным, но это уже двусмысленно. Получает ли участник, потративший 500, скидку 5%? В предложении говорится «эти приказы», ​​поэтому мы предполагаем, что нет. Имейте это в виду, поскольку BDD предназначен именно для того, чтобы задавать такие вопросы на ранних стадиях.

Создание его с помощью TDD

TDD следует короткому циклу, известному как красный, зеленый, рефакторинг:

Шаг Что ты делаешь
Красный Напишите один тест на поведение, которого еще не существует, и посмотрите, как он провалится.
Зеленый Напишите простейший код, который позволит пройти
Рефакторинг Улучшайте код, сохраняя тесты зелеными

Это наши тесты, по одному на каждое правило:

class DiscountTests(unittest.TestCase):
    def test_no_discount_below_1000(self):
        self.assertEqual(discount(999, False), 0)

    def test_ten_percent_from_1000(self):
        self.assertEqual(discount(1000, False), 100)

    def test_member_gets_extra_five_percent(self):
        self.assertEqual(discount(1000, True), 150)

Затем мы написали код в три этапа, запуская тесты после каждого. Строгий сеанс TDD добавляет по одному тесту за раз, и это показывает тот же прогресс:

Этап 1: самое простое

def discount(total, is_member):
    return 0

# 3 tests, 2 failed
#   test_member_gets_extra_five_percent
#   test_ten_percent_from_1000

Возврат нуля выглядит глупо, но он доказывает, что тесты действительно могут провалиться, и единственный тест, который он проходит, — это правило «без скидок».

Этап 2: добавьте порог

def discount(total, is_member):
    if total >= 1000:
        return total * 0.1
    return 0

# 3 tests, 1 failed
#   test_member_gets_extra_five_percent

Этап 3: добавьте участников и очистите

def discount(total, is_member):
    rate = 0.1 if total >= 1000 else 0
    if is_member:
        rate += 0.05
    return round(total * rate, 2)

# 3 tests, 0 failed

Все трое проходят. Но прочтите эту версию внимательно. Оно дает участнику, потратившему 500, скидку 5%, а это не то, что, как мы предполагали, подразумевало это правило. Ни один тест не охватил этот случай, поэтому ничто не выявило его. TDD защищает только то поведение, которое вы собирались протестировать. Это реальное ограничение, и именно поэтому разговоры о примерах так важны.

Почему цикл имеет значение

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

В нашем руководстве по pytest показан более удобный способ написания подобных тестов, а анализ граничных значений объясняет, почему мы выбрали 999 и 1000 в качестве значений.

Сборка с помощью BDD

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

Tester:  What about a member spending 500?
Product: Good question. No discount. It has to reach 1000 first.
Dev:     And exactly 1000 counts?
Product: Yes, 1000 or more.

Этот обмен обнаружил бы проблему в нашем TDD-коде. Затем они записывают свои примеры в структурированном формате под названием Gherkin:

Feature: Order discounts

  Scenario: Member reaches the discount threshold
    Given a member with a cart worth 1000
    When they view the amount to pay
    Then the amount to pay is 850

  Scenario: Member below the threshold gets no discount
    Given a member with a cart worth 500
    When they view the amount to pay
    Then the amount to pay is 500
Ключевое слово Цель
Учитывая Исходная ситуация
Когда Действие или событие
Тогда Ожидаемый результат

Любой член команды может прочитать это и сказать «да, это правильно» или «нет, это неправильно». Даже если вы никогда не автоматизируете его, сценарий уже проделал полезную работу.

Соединение шагов с кодом

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

@step("a member with a cart worth 1000")
def given(ctx):
    ctx["cart"] = Cart(is_member=True)
    ctx["cart"].add(1000)

@step("they view the amount to pay")
def when(ctx):
    ctx["amount"] = ctx["cart"].payable()

@step("the amount to pay is 850")
def then(ctx):
    assert ctx["amount"] == 850

# ok Given a member with a cart worth 1000
# ok When they view the amount to pay
# ok Then the amount to pay is 850

Реальные инструменты добавляют параметры, так что один шаг может соответствовать как «1000», так и «500», а также отчетам. В результате получается живая документация: простое описание системы, которое громко терпит неудачу, если перестает быть правдой.

Совет: Ценность BDD заключается в разговоре. Команды, в которых один человек пишет Gherkin самостоятельно после завершения кода, получают стоимость инструмента, практически не получая никакой выгоды.

Написание хороших сценариев

Слабый Лучше
Когда я нажимаю кнопку с идентификатором «btn-77» Когда я применяю купон
Тогда результат правильный Тогда сумма к оплате составит 850.
Двадцать шагов в одном сценарии Одно поведение на сценарий
Описывает экран Описывает деловые намерения

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

Использование обоих вместе

Эти два процесса естественным образом вписываются в рабочий процесс «снаружи внутри»:

  1. Команда согласовывает поведение и пишет сценарий BDD. Это не удается, потому что еще ничего не существует.
  2. Разработчик использует TDD для создания необходимых небольших модулей.
  3. Юнит-тесты проходят успешно, и в конечном итоге сценарий тоже.
  4. Все работает в вашем конвейере CI/CD.

Держите каждого на должном уровне. У вас должно быть несколько сценариев для важных действий и множество быстрых модульных тестов для детализации. Наше руководство по модульному и интеграционному тестированию покрывает баланс.

Инструменты

Язык TDD (юнит-тестирование) БДД
Питон pytest, юниттест веди себя, pytest-bdd
JavaScript Джест, Витест Cucumber.js
Ява Юнит, ТестНГ Огурец-JVM
.NET хЮнит, НЮнит Рекнролл, SpecFlow

Когда использовать каждый

TDD хорошо подходит, когда:

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

BDD хорошо подходит, когда:

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

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

Распространенные ошибки

  • Отношение к BDD как к инструменту тестирования. Cucumber без совместной работы — это просто многословный способ написания тестов.
  • Тестирование реализации в TDD. Тесты, связанные с личными деталями, ломаются во время каждого рефакторинга.
  • Пропуск этапа рефакторинга. Вы получаете прохождение тестов поверх беспорядочного кода.
  • Написание тестов после кода и название его TDD. Это по-прежнему полезно, но вы теряете обратную связь по дизайну.
  • Написание слишком большого количества сценариев пользовательского интерфейса. Они становятся медленными и нестабильными. См. ненадежные тесты.
  • Погоня за показателями охвата. Как показывает наш пример, хорошее освещение по-прежнему не учитывает поведение, которое никто не учитывает.

Итоги

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

Часто задаваемые вопросы

В чем основная разница между TDD и BDD?

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

Можете ли вы использовать TDD и BDD вместе?

Да, и многие команды так делают. Сценарии BDD определяют функции извне, а TDD управляет меньшими единицами кода, находящимися под ними.

BDD лучше, чем TDD?

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

Что такое Корнишон?

Корнишон — это структурированный простой язык для написания сценариев с использованием таких ключевых слов, как «Дано», «Когда» и «Тогда». Такие инструменты, как Cucumber, могут его запустить.

Замедляет ли TDD разработку?

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

Продолжайте учиться

Работайте с Stack Quora

Нужна помощь с тестированием, WordPress или SEO?

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

Продолжайте читать

Больше руководств по тестирование, искусственный интеллект и современные разработки

Понравилась эта статья? Выберите тему и сразу приступайте к нашим новейшим руководствам.

Искусственный интеллект

Объяснение галлюцинаций искусственного интеллекта: почему языковые модели все выдумывают и как их уменьшить

Галлюцинации ИИ объяснили: что это такое, почему языковые модели их создают, распространенные типы, как уменьшить их с помощью заземления и подсказо…

Читать статью →
DevOps

Объяснение переменных среды: файлы .env, секреты и правильно выполненная конфигурация

Переменные среды объясняются на примерах Python, которые мы запускали: их чтение и установка, почему каждое значение является строкой, файлы .env, н…

Читать статью →
Разработка ПО

Объяснение ограничения скорости API: алгоритмы, заголовки и обработка ошибок 429

Ограничение скорости API объясняется с помощью проведенного нами моделирования: сегмент токенов, фиксированное окно, скользящее окно, 429 ответов, з…

Читать статью →
Автоматизация тестирования

Издевательство в Python: unittest.mock, патч и ошибки, из-за которых тесты лгут

Издевательство на Python с помощью unittest.mock, протестировано: Mock и return_value, Side_effect, исправление использования имени, спецификация и …

Читать статью →
Тестирование ПО

Объяснение покрытия кода: покрытие линий или ветвей и что на самом деле означает 100%

Покрытие кода объяснено с помощью реального запуска покрытия.py: покрытие строк, ветвей и условий, чтение отчета, почему 100%-ное покрытие все еще м…

Читать статью →
Базы данных и SQL

DELETE, TRUNCATE и DROP в SQL: различия, откат и когда использовать каждый из них

Объяснение DELETE, TRUNCATE и DROP на примере протестированного SQL: что каждый из них удаляет, откат, триггеры, сброс идентификаторов, скорость и ч…

Читать статью →
Базы данных и SQL

Объяснение представлений SQL: создавайте, используйте и избегайте ловушек, с примерами

Представления SQL, объясненные с помощью запросов, которые мы выполняли: создание представления, результаты в реальном времени, скрытие столбцов, пр…

Читать статью →
Разработка ПО

Интерфейс TypeScript и тип: реальные различия, протестированные с помощью компилятора

Интерфейс TypeScript против типа, проверенный реальным компилятором: что могут делать оба, что может делать только один, слияние объявлений, расшире…

Читать статью →
Разработка ПО

Объяснение Python *args и **kwargs: гибкие функции с понятными примерами

Python *args и **kwargs, объясненные с помощью кода, который мы запускали: упаковка и распаковка, порядок параметров, аргументы только по ключевым с…

Читать статью →
Разработка ПО

Лямбда-функции Python: синтаксис, реальное использование и когда их не следует использовать

Лямбда-функции Python, объясненные с помощью кода, который мы запускали: синтаксис, сортировка с помощью ключа, карты и фильтра, замыкания, ловушка …

Читать статью →
Искусственный интеллект

Что такое ИИ-агенты? Как они работают: можно запустить простой цикл агента

Что такое агенты ИИ? Простое руководство по циклу агента, инструментам, памяти и ограничениям, с небольшим циклом Python, который мы запустили, реал…

Читать статью →
DevOps

Мониторинг и наблюдаемость: реальная разница с журналами, метриками и трассировками

Объяснение мониторинга и наблюдаемости: известные и неизвестные сбои, журналы, метрики и трассировки, пошаговое руководство по инцидентам при оформл…

Читать статью →
DevOps

Docker Volumes против Bind Mounts: правильное сохранение данных контейнера

Объяснение томов Docker и монтирования привязки: почему исчезают данные контейнера, именованные тома, монтирование привязки, tmpfs, примеры создания…

Читать статью →
Автоматизация тестирования

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

TDD и BDD объясняются с помощью одной функции скидки, созданной в обоих направлениях: красно-зеленый рефакторинг с кодом, который мы запускали, сцен…

Читать статью →
Разработка ПО

Git merge vs rebase: отличия, примеры и когда что использовать

Git merge vs rebase с реальным выводом log, сравнительной таблицей, золотым правилом rebase и безопасным рабочим процессом для команды.

Читать статью →
Разработка ПО

Генераторы списков в Python: синтаксис, примеры и когда их избегать

Генераторы списков в Python: синтаксис, фильтры, if-else, вложенные циклы, измеренное время и случаи, когда обычный цикл for лучше.

Читать статью →
Базы данных и SQL

SQL JOIN: объяснение с примерами (Inner, Left, Right, Full)

Разберите SQL JOIN шаг за шагом на примерах таблиц и запросов: INNER, LEFT, RIGHT, FULL, CROSS и SELF, а также частые ошибки и советы по производите…

Читать статью →