Являются ли тесты для разработки через тестирование (TDD) всегда юнит-тестами?

41

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

user1364368
источник
6
Нередко используют более одного уровня красного / зеленого / рефактора, вложенных друг в друга. Например, вы можете следить за красным / зеленым / рефактором во время написания приемочных / поведенческих тестов, где «зеленая» фаза самого приемочного теста содержит несколько итераций красного / зеленого / рефакторинга модульных тестов.
Шон Бертон,
1
Название не соответствует содержанию вопроса. Заголовок «тесты всегда юнит-тесты » (ответ: нет, могут быть и другие типы тестов, кроме юнит-тестов), содержание спрашивает: «Вы должны сначала написать тест?».
AnoE
@AnoE Первое предложение содержания является только вступительным заявлением. Во втором предложении не спрашивается, должен ли сначала быть написан тест, но можно ли использовать подход TDD для методов тестирования, отличных от TDD.
user1364368
@ user1364368, не стесняйтесь переформулировать вопрос немного, по крайней мере, я был смущен тем, каково ваше намерение при первом чтении, и вопрос с наибольшим количеством голосов, хотя решение обоих ваших предложений также заметно начинается с первого.
AnoE
@AnoE Я изменил начало второго предложения, чтобы прояснить, что же это за вопрос.
user1364368

Ответы:

27

Все, что от вас требует TDD, - это написать неудачный тест, а затем изменить свой код, чтобы он прошел.

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

Дэвид Арно
источник
59

Красный зеленый цикл рефакторинга построен по одному очень здравому принципу:

Только тесты доверия, которые вы видели, проходят и не проходят.

Да, это работает и с автоматизированными интеграционными тестами. Также ручные тесты. Черт возьми, он работает на тестерах автомобильных аккумуляторов. Вот как вы тестируете тест.

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

candied_orange
источник
1
Это также одна из причин, по которой отрицательное тестирование важно при тестировании на наличие ошибки: вы хотите убедиться, что все остальное работало бы, поэтому два теста (один выдает точно ожидаемую ошибку, а другой не выдает ошибку) рядом с друг с другом помогает повысить уверенность в том, что в будущем это красно-зеленое состояние сохранится.
Матье М.
12

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

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

Док Браун
источник
8

Я понимаю разработку, основанную на тестировании, что вам разрешено писать продуктивный код только при неудачном (красном) модульном тесте.

Нет. Вы можете написать только самый простой код, чтобы изменить сообщение теста. Это ничего не говорит о том, что за тест.

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

Теперь вы пишете простейший производственный код, который может изменить сообщение об ошибке. Запустите тест снова, убедитесь, что сообщение об ошибке изменилось, что оно изменилось в правильном направлении, и что код изменил сообщение по правильной причине. (В идеале, сообщение об ошибке должно исчезнуть, и тест должен пройти, но чаще всего лучше сделать небольшие изменения, изменяя сообщение, а не пытаться заставить тест пройти тест за один раз - вот причина почему разработчики тестовых сред тратят столько усилий на сообщения об ошибках!)

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

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

Этот средний цикл теперь повторяется до тех пор, пока не пройдет приемочный тест, и теперь вы можете выполнять рефакторинг по всей системе.

Теперь вы выбираете следующий критерий принятия, и внешний цикл начинается снова.

Кент Бек, «первооткрыватель» TDD (ему не нравится термин «изобретатель», он говорит, что люди этим занимались все время, он просто дал ему имя и написал об этом книгу) использует аналогию из фотографии и называет это "увеличение и уменьшение".

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

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

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

Вы действительно не применяете TDD к тестам. Вы применяете это ко всему процессу разработки. Вот что означает «управляемая» часть Test- Driven -Development: вся ваша разработка основана на тестах. Тесты не только управляют кодом, который вы пишете, они также определяют, какой код писать, какой код писать дальше. Они управляют вашим дизайном. Они скажут вам, когда вы закончите. Они говорят вам, над чем работать дальше. Они рассказывают вам о недостатках дизайна в вашем коде (когда тесты трудно писать).

Кейт Брейтуэйт создал упражнение, которое он называет TDD, как будто вы это имели в виду . Он состоит из набора правил (основанных на Трех правилах TDD дяди Боба Мартина , но гораздо более строгих), которым вы должны строго следовать и которые направлены на то, чтобы более строго применять TDD. Лучше всего работает с парным программированием (чтобы ваша пара могла убедиться, что вы не нарушаете правила) и с инструктором.

Правила таковы:

  1. Напишите ровно один новый тест, самый маленький тест, который вы, возможно, указывает на решение
  2. Видеть это не удастся; ошибки компиляции считаются ошибками
  3. Пройдите тест из (1), написав наименьший код реализации, который вы можете использовать в методе test .
  4. Рефакторинг для устранения дублирования, а также по мере необходимости для улучшения дизайна. Будьте строги в использовании этих ходов:
    1. вам нужен новый метод - дождитесь времени рефакторинга, затем ... создайте новые (не тестовые) методы, выполнив один из них, и никак иначе:
      • предпочтительнее: сделать метод извлечения для кода реализации, созданного в соответствии с (3), чтобы создать новый метод в тестовом классе, или
      • если вы должны: переместить код реализации согласно (3) в существующий метод реализации
    2. Вы хотите новый класс - подождите до времени рефакторинга, затем ... создайте не тестовые классы, чтобы обеспечить назначение для метода Move, и ни по какой другой причине
    3. заполнить классы реализации методами, выполнив Move Method, и никак иначе

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

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

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

Ссылка : "Разработка через тестирование на примере", Кент Бек

Кент Бек описывает, что он подразумевает под «модульным тестом» в главе 32 - «Освоение TDD».

Джейсон Десросье
источник
1

Я не читал об этом книги, и при этом я не следую все время «стандартным» методам TDD, но, на мой взгляд, основной смысл философии TDD, с которым я полностью согласен, заключается в том, что сначала нужно определить успех , Это важно на каждом уровне дизайна, от "Какова цель этого проекта?" на "Какими должны быть входы и выходы этого маленького метода?"

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

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


источник
1

В докладе «Разработка через тестирование»: это не то, что мы имели в виду. Стив Фриман показывает следующий слайд общей картины TDD (см. Ответ ниже на рисунке). Это включает в себя этап «Написать неудачный сквозной тест», за которым следует «Написать неудачный юнит-тест». (Нажмите, чтобы увеличить, в правом верхнем углу)

Так что нет в TDD тесты не всегда юнит-тесты.

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

введите описание изображения здесь

Нильс ван Реймерсдал
источник
-1

Нет, его нельзя применять к другим типам тестов по простой практической причине: другие типы тестов выполняются слишком долго.

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

BЈовић
источник
1
Это неверно: в зависимости от программы и теста (и языка) сквозные интеграционные тесты могут легко выполняться менее чем за 3 секунды. Вполне возможно запустить полный комплексный набор тестов за очень короткое время, даже если он хорошо спроектирован. Так что «не могу» довольно сильно.
Джонатан В ролях
@jcast Я никогда не видел ничего более быстрого. Мои функциональные тесты в моем предыдущем проекте заняли 30 секунд, и это быстро. Интеграция еще дольше. В моем случае больше ничего не имело смысла. Кроме того, модульные тесты являются самыми быстрыми из всех видов тестов - поэтому имеет смысл использовать их.
BЈовић