Чому б не написати всі тести одразу під час виконання TDD?


54

Цикл червоний - зелений - Refactor для TDD добре встановлений і прийнятий. Ми пишемо один невдалий одиничний тест і пропускаємо його як можна простіше. У чому полягають переваги такого підходу у написанні багатьох невдалих одиничних тестів для класу та змушення їх пройти за один раз.

Тестовий набір все ще захищає вас від написання неправильного коду або помилок на етапі рефакторингу, тож яка шкода? Іноді простіше написати спочатку всі тести для класу (або модуля) як форму "мозкового дампа", щоб швидко записати всю очікувану поведінку за один раз.


20
Робіть те, що найкраще підходить для вас (після деяких експериментів). Сліпо дотримуватися догми ніколи не є доброю справою.
Майкл Боргвардт

6
Смію сказати, що писати всі ваші тести відразу, як і писати весь код вашої програми одразу.
Майкл Харен

1
@MichaelHaren Всі тести для класу (або функціонального модуля), вибачте за плутанину
RichK

3
Вирішення проблеми "сміттєзвалища": Іноді в тестуванні / кодуванні виникають моменти, коли ви усвідомлюєте необхідність в декількох різних конкретних вхідних тестах, і є тенденція захотіти скористатися чіткістю цієї реалізації, перш ніж ви відволікаєтесь на деталі кодування. Зазвичай мені це вдається, підтримуючи окремий список (наприклад, Mylyn), або ж із переліком коментарів до класу Test, які я хочу пам'ятати, щоб перевірити (наприклад, // test null case). Однак я все одно кодую лише один тест за один раз, і замість цього систематично працюю над своїм списком.
Сем Голдберг

1
добре, я не знаю, чому ніхто про це не згадував, але ви не можете написати всі тести одразу. Складання всіх тестів перед рукою точно так само, як і BDUF . А чого нас навчила історія про BDUF? Це майже ніколи не працює.
Сонго

Відповіді:


49

Тестова конструкція полягає в тому, щоб правильно визначити ваш API , а не код.

Перевага написання найпростіших помилкових тестів спочатку полягає в тому, що ви отримуєте API (який, по суті, це ви проектуєте на ходу) максимально просто. Вперед спереду.

Будь-яке майбутнє використання (яке є наступними тестами, які ви пишете) піде від початкового простого дизайну, а не від неоптимального дизайну, що вирішує більш складні випадки.


Відмінні бали! Ми іноді настільки занурені в тестування коду, що іноді ігноруємо, наскільки важливими можуть бути API та модель домену, перш ніж навіть написати перший тест.
maple_shaft

+1 за фактично звертаючись до наміру Test Driven розвитку.
Джошуа Дрейк

76

Коли ви пишете один тест, ви зосереджуєтесь на одному .
За допомогою багатьох тестів ви поширюєте свою увагу на багато завдань, тому це не дуже гарна ідея.


8
Хто би спростував це ?!
CaffGeek

6
@Chad Я не був голосовим проти, але я вважаю, що ця відповідь пропускає очевидне. Розробка тестового керування полягає у використанні тестів для керування дизайном коду. Ви пишете тест індивідуально для того, щоб розвинути дизайн, а не лише для перевірки. Якби мова йшла лише про тестові артефакти, то це була б чудова відповідь, але як це не вистачає певної важливої ​​інформації.
Джошуа Дрейк

7
Я не спростував цього, але; Я подумав про це. Занадто коротка відповідь на складне запитання.
Марк Вестон

2
+1 за концентрацію на одній речі за один раз, наша здатність до багатозадачності завищена.
cctan

Це найпростіша відповідь, яка могла б спрацювати.
ДНК

26

Однією з труднощів при написанні одиничних тестів є те, що ви пишете код і який сам по собі може бути схильним до помилок. Існує також можливість, що, можливо, вам потрібно буде змінити свої тести пізніше в результаті зусиль рефакторингу під час написання коду реалізації. Що стосується TDD, це означає, що ви потенційно можете занадто захопитися тестуванням і виявити, що вам потрібно переписати багато по суті "неперевіреного" тестового коду, коли ваша реалізація дозріває протягом проекту. Один із способів уникнути подібної проблеми - просто зосередитись на виконанні однієї єдиної речі за один раз. Це гарантує мінімізацію впливу будь-яких змін на ваші тести.

Звичайно, це значною мірою зводиться до того, як ви пишете свій тестовий код. Ви пишете одиничне тестування для кожного окремого методу чи ви пишете тести, орієнтовані на особливості / вимоги / поведінку? Іншим підходом може бути використання підходу, керованого поведінкою з відповідним фреймворком, і зосередження уваги на написанні тестів так, ніби вони є специфікаціями. Це означатиме або прийняття методу BDD, або адаптацію тестування BDD, якщо ви хочете формальніше дотримуватися TDD. Крім того, ви можете повністю дотримуватися парадигми TDD, але змінювати спосіб написання тестів, щоб замість того, щоб повністю зосередитися на методах тестування індивідуально, ви тестуєте поведінку як правило як засіб для задоволення специфіки вимог, які ви реалізуєте.

Незалежно від конкретного підходу, який ви використовуєте, у всіх випадках, які я описав вище, ви використовуєте тестовий підхід, тому, хоча це може бути спокусливо просто завантажити ваш мозок у прекрасний набір тестів, ви також хочете боротися з спокуса зробити більше, ніж абсолютно необхідно. Щоразу, коли я збираюся запустити новий тестовий набір, я починаю повторювати YAGNI собі, а іноді навіть кидаю це в коментар до свого коду, щоб нагадати мені залишатися зосередженим на тому, що негайно важливо, і робити лише необхідний мінімум, щоб задовольнити вимоги функції, яку я збираюся реалізувати. Дотримуючись Red-Green-Refactor допомагає вам це зробити.


Я щасливий, що ти вказав на різницю між тим, як пише свій тестовий код. Деякі люблять писати єдиний тест головного блоку, який охоплює всі реалістичні можливості введення в одну функцію або метод. Інші застосовують більш BDD підхід за допомогою своїх одиничних тестів. Ця відмінність важлива при визначенні того, чи важливим є написання цілого набору тестів, це обов'язково погана практика чи ні. Прекрасне розуміння!
maple_shaft

17

Я думаю, роблячи це, ви пропускаєте процес TDD. Лише написавши всі свої тести на початку, ви насправді не проходили процес розробки за допомогою TDD. Ви просто здогадуєтеся наперед, які тести вам знадобляться. Це буде дуже різний набір тестів від тих, які ви закінчуєте писати, якщо ви робите їх по черзі, коли розробляєте свій код. (Якщо тільки ваша програма не матиме банального характеру.)


1
Більшість застосунків для бізнесу та підприємств мають технічний характер тривіальне і бачать, як більшість додатків є бізнесом та підприємствами, тому більшість додатків є також тривіальними за своєю природою.
maple_shaft

5
@maple_shaft - технологія може бути тривіальною, але бізнес-правила - ні. Спробуйте створити додаток для 5 менеджерів усіх, хто має різні вимоги і відмовляються слухати деякі BS про ваш простий, елегантний, менший за мінімалізм дизайн.
JeffO

5
@JeffO 1) Це не BS. 2) Елегантний мінімалістичний дизайн вимагає хороших навичок розробки програмного забезпечення. 3) Можливість пом'якшити вимоги 5 різних менеджерів, які не мають більше 5 хвилин на тиждень, щоб витрачати з вами і все-таки знімати мінімалістичний дизайн, вимагає відмінного розробника програмного забезпечення. Порада: Розробка програмного забезпечення - це не просто навички кодування, це переговори, бесіда та отримання права власності. Ви повинні бути собакою Альфа і інколи кусатися назад.
maple_shaft

1
Якщо я правильно розумію, ця відповідь задає питання.
Конрад Рудольф

1
@maple_shaft Я думаю, що до цього ставився Джефф О зі своїм коментарем, ні?
ZweiBlumen

10

Я "пишу" всі тести, які я можу придумати наперед, під час "штурму мозку", проте пишу кожен тест як один коментар, що описує тест.

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

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

Тепер, якщо ви використовуєте систему на зразок специфічного потоку, коли тести написані на "англійській мові", ви можете змусити клієнтів погодитися на набір тестів, поки у вас є час, а не створити єдиний тест.


1
Так, погоджуючись з відповідями вище, які в першу чергу вказують на проблеми з кодуванням всіх ваших тестів, я вважаю дуже корисним скинути моє загальне розуміння того, як поточний метод повинен вести себе як набір тестових описів без будь-якого коду. Процес їх запису має тенденцію з’ясувати, чи я повністю розумію, що вимагається від коду, про який я буду писати, і чи є крайові випадки, про які я не думав. Мені здається, що набагато зручніше кодувати перший тест, а потім змусити його пройти після того, як я окреслив свій «огляд» того, як має працювати метод.
Марк Вестон

10

Ідея TDD - це швидкі ітерації.

Якщо у вас є велика кількість тестів, які потрібно писати, перш ніж писати код, важко повторно переробити код.

Без легкого рефакторингу коду ви втрачаєте масу переваг TDD.


5

З мого (обмеженого) досвіду роботи з TDD, я можу вам сказати, що кожного разу, коли я порушував дисципліну написання одного тесту за один раз, справи йшли погано. У цю пастку легко потрапити. "О, цей метод тривіальний, - подумаєте ви самі, - тому я просто вибию ці два інші пов'язані тести і продовжуватиму рухатись". Ну, вгадайте, що? Ніщо не таке банальне, як здається. Кожного разу, коли я потрапляв у цю пастку, я закінчував налагодження чогось, що я вважав легким, але виявилося, що у нас є дивні кутові випадки. А оскільки я продовжував писати кілька тестів одночасно, було дуже багато роботи, щоб відстежити, де помилка.

Якщо вам потрібен мозковий дамп інформації, у вас є маса варіантів:

  • Дошка
  • Історії користувачів
  • Коментарі
  • Добре ручка і папір

Зауважте, що ніде в цьому списку немає компілятора. :-)


5

Ви припускаєте, що знаєте, як буде виглядати ваш код, перш ніж його написати. TDD / BDD - це стільки ж процесу проектування / відкриття, скільки і процес QA. Для даної функції ви пишете найпростіший тест, який би підтвердив, що функція задоволена (іноді для цього може знадобитися кілька через складність функції). Цей перший тест, який ви пишете, завантажений припущеннями про те, як буде виглядати робочий код. Якщо ви пишете весь тестовий набір перед тим, як написати перший рядок коду для його підтримки, ви робите літанію неперевірених припущень. Замість цього напишіть одне припущення та перевірте це. Потім напишіть наступне. У процесі перевірки наступного припущення ви можете просто порушити попереднє припущення, тому вам доведеться повернутися назад або змінити це перше припущення на відповідність дійсності або змінити реальність, так що перше припущення все ще застосовується.

Подумайте про кожен одиничний тест, який ви пишете як теорію, у науковому зошиті. Коли ви заповнюєте зошит, ви підтверджуєте свої теорії та формуєте нові. Іноді доведення нової теорії спростовує попередню теорію, тому вам доведеться її виправити. Простіше довести одну теорію за один раз, ніж намагатися довести сказати 20 відразу.


TDD припускає, що ви знаєте, як буде виглядати ваш код ще до того, як ви його також напишите, лише меншими шматками.
Майкл Шоу

4

TDD - це дуже ітеративний підхід, який (на мій досвід) краще відповідає реальним світовим шляхам розвитку. Зазвичай моя реалізація формується поступово під час цього процесу, і кожен крок може поставити додаткові запитання, уявлення та ідеї для тестування. Це ідеально, щоб я міг зосередитись на фактичному завданні, і є дуже ефективним, оскільки мені потрібно зберігати обмежену кількість речей у короткотерміновій пам'яті в будь-який момент часу. Це в свою чергу зменшує можливість помилок.

Ваша ідея - це підхід Big Test Up Front, з яким IMHO складніше впоратися, і може стати більш марним. Що робити, якщо на середині вашої роботи ви усвідомлюєте, що ваш підхід не є хорошим, ваш API недосконалий, і вам потрібно запустити все спочатку або використовувати замість нього бібліотеку сторонніх виробників? Тоді багато роботи, складеної над написанням ваших тестів наперед, стають витраченими витратами.

Це сказало, якщо це працює для вас, добре. Я можу собі уявити, що якщо ви працюєте за фіксованою, детальною технічною специфікацією, у домені, з яким ви тісно переживаєте, та / або над досить невеликим завданням, можливо, ви будете готові більшість або всі необхідні тестові справи, і ваша реалізація зрозуміла прямо з початок. Тоді, можливо, має сенс почати з написання всіх тестів одразу. Якщо ваш досвід полягає в тому, що це робить вас більш продуктивними в довгостроковій перспективі, вам не потрібно надто хвилюватися щодо правил :-)


4

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

Тепер, якщо ви не обмежуєтеся писати код, щоб змусити їх пройти "за один раз", а скоріше написати достатньо коду, щоб пройти один тест за один раз, він все одно може працювати. Вам доведеться мати більше дисципліни, щоб не просто йти вперед і писати більше коду, ніж потрібно. Після того, як ви починаєте цей шлях, ви залишаєте себе відкритим для написання коду більше, ніж описують тести, що може бути неперевіреним , принаймні в тому сенсі, що він не керується тестом і, можливо, в тому сенсі, що він не потрібен (або здійснено) будь-яким тестом.

Вказівки щодо того, що повинен робити метод, як коментарі, розповіді, функціональна специфікація тощо, цілком прийнятні. Я б зачекав, щоб перевести їх у тести по одному, однак.

Інша річ, яку ви можете пропустити, написавши тести відразу, - це процес мислення, завдяки якому проходження тесту може спонукати вас думати про інші тестові випадки. Без банку існуючих тестів вам потрібно продумати наступний тестовий випадок у контексті останнього проходження тесту. Як я вже говорив, дуже добре уявити, що слід зробити методом, дуже добре, але я багато разів знаходив нові можливості, які я не вважав апріорі, але які виникали лише в процесі написання тести. Існує небезпека, що ви можете їх пропустити, якщо ви конкретно не звикли думати, які нові тести я можу написати, що у мене ще немає.


3

Я працював над проектом, де розробники, які написали (невдалі) тести, відрізнялися від розробників, які впроваджували необхідний код, щоб вони пройшли, і я вважав це дійсно ефективним.

У цьому випадку були написані лише тести, що стосуються поточної ітерації. Тож те, що ви пропонуєте, цілком можливо в такому сценарії.


2
  • Тоді ви намагаєтесь зосередитися на занадто багато речей одночасно.
  • Впроваджуючи, щоб усі тести пройшли, у вас немає робочої версії програми. Якщо вам доведеться багато впроваджувати, то у вас не буде робочої версії протягом тривалого часу.

2

Цикл Red-Green-Refactor - це контрольний список, призначений для розробників, новинок TDD. Я б сказав, що це гарна ідея дотримуватися цього контрольного списку, доки ви не дізнаєтесь, коли слід дотримуватися його та коли ви зможете його порушити (тобто доки не знаєте, не потрібно ставити це питання на stackoverflow :)

Зробивши TDD протягом майже десятиліття, я можу вам сказати, що я дуже рідко, якщо і коли-небудь, пишу багато провальних тестів, перш ніж писати виробничий код.


1

Ви описуєте BDD, де деякий зовнішній зацікавлений сторон має виконавчу специфікацію. Це може бути корисно, якщо є заздалегідь визначена передня специфікація (наприклад, специфікація формату, промисловий стандарт або коли програміст не є експертом домену).

Звичайний підхід полягає в тому, щоб поступово охоплювати все більше і більше тестів на прийняття, що є прогресом, помітним керівнику проекту та замовнику.

Зазвичай у вас є ці тести, визначені та виконані в рамках BDD, таких як Огірок, Фітнессе або щось подібне.

Однак, це не те , що ви переплутати з юнітом - тестами, які набагато ближче до вошивий шорстким деталей реалізації з великою кількістю крайових випадків , пов'язаними з API, питання ініціалізації і т.д. в значній мірі зосереджені на випробувальному , який є артефактом реалізації .

Дисципліна червоно-зеленого рефактора має багато переваг, і єдине перевершення, на яке ви можете сподіватися, набравши їх передньою стороною, - це зламати рівномірність.


1

Один тест на час: головна перевага - зосередженість на одному. Подумайте про перший дизайн на глибині: ви можете піти вглиб і зосередитись з швидким циклом зворотного зв'язку. Ви можете пропустити всю проблему! Ось цей момент (великий) рефакторинг вступає в гру. Без нього TDD не працює.

Всі тести: аналіз та проектування можуть розкрити вам більше масштабу проблеми. Подумайте про перший дизайн. Ви аналізуєте проблему з більшої точки зору і додаєте досвід із досвіду. Це за своєю суттю складніше, але може принести цікаву користь - менше рефакторингу - якщо ви зробите це "просто достатньо". Слідкуйте за тим, щоб легко переаналізувати і при цьому повністю пропустити позначку!

Мені важко взагалі рекомендувати віддавати перевагу тому чи іншому, адже факторів багато: досвід (особливо з тією ж проблемою), доменні знання та вміння, дружелюбність коду для рефакторингу, складність проблеми ...

Я б припустив, якщо ми зосередимося на більш типових бізнес-програмах, то TDD із своїм підходом до найпростішого випробування та помилок зазвичай виграє з точки зору ефективності.


1

Якщо припустити, що ваш тестовий фреймворк це підтримує, то, що я б запропонував, це те, що замість того, щоб реалізовувати тести, які ви хочете скористатися, замість цього випишіть описові очікувані тести, які ви згодом реалізуєте. Наприклад, якщо ваш API повинен робити foo і bar, але не biz, просто додайте наступний код (цей приклад знаходиться в rspec) для свого тестового набору, а потім атакуйте їх по черзі. Ви швидко вгамуєте свої думки і зможете вирішити всі ваші проблеми по черзі. Коли всі тести пройдуть, ви дізнаєтесь, коли ви вирішили всі свої проблеми, які виникли під час вашого тормозного нападу.

describe "Your API" do

  it "should foo" do
    pending "braindump from 4/2"
  end

  it "should bar" do
    pending "braindump from 4/2"
  end

  it "should not biz" do
    pending "braindump from 4/2"
  end

end
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.