Чи завжди тести на тестові розробки (TDD) завжди є одиничними тестами?


41

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


6
Не рідкість використовувати більше одного різного рівня червоного / зеленого / рефактора, вкладеного один в одного. Наприклад, ви можете слідкувати за червоним / зеленим / рефактором під час написання тестів на прийняття / поведінку, де сама «зелена» фаза тесту на прийняття містить декілька червоних / зелених / рефакторних ітерацій одиничних тестів.
Шон Бертон

1
Заголовок не відповідає змісту запитання. Заголовок "- це тести завжди одиничні тести " (відповідь: ні, можуть бути інші типи тестів, окрім одиничних тестів), зміст запитує "чи ти повинен написати тест спочатку?".
AnoE

@AnoE Перше речення змісту - лише вступне твердження. Речення в секундах не запитує, чи потрібно спочатку писати тест, але якщо підхід TDD може бути використаний для методів тестування, інших, ніж TDD.
користувач1364368

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

@AnoE Я змінив початок другого речення, щоб зрозуміти, що таке власне питання.
користувач1364368

Відповіді:


27

Все, що вимагає від вас TDD, - це те, що ви написали невдалий тест, а потім змінили свій код, щоб він пройшов.

Зазвичай "одиничні тести" є невеликими і швидкими і перевіряють окрему частину коду окремо. Оскільки вони швидкі, це також робить цикл червоного / зеленого / рефактора також швидким. Однак вони страждають від випробування лише деталей у відриві. Тож вам потрібні й інші тести (інтеграція, прийняття тощо). Досі добре застосовувати ті самі принципи: написати тест, який не працює, а потім змінити код, щоб він працював. Просто пам’ятайте, що вони зазвичай повільніші, тому можуть впливати на час циклу червоний / зелений / рефактор.


59

Цикл червоного зеленого рефактора побудований за одним дуже здоровим принципом:

Тільки тести довіри, які ви бачили, проходять і провалюються.

Так, це працює і з автоматизованими тестами інтеграції. Також ручні тести. Чорт, це працює на автомобільних тестерах акумуляторів. Це те, як ви випробовуєте тест.

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


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

12

Однак мені цікаво, чи можна застосовувати тестовий підхід до інших форм тестів.

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


8

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

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

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

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

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

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

Цей середній цикл тепер повторюється до тих пір, поки не пройде випробування на прийняття, і в цей момент ви можете робити рефактори для всієї системи.

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

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

Примітка: не завжди потрібні три рівня тестів. Можливо, іноді потрібно більше. Частіше потрібно менше. Якщо ваші функціональні можливості невеликі, а ваші функціональні тести швидкі, ви можете пройти без (або з меншими одиницями тестів). Часто потрібні лише приймальні тести та одиничні тести. Або ваші критерії прийняття настільки дрібні, що ваші тести прийняття є функціональними тестами.

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

Однак мені цікаво, чи можна застосовувати тестовий підхід до інших форм тестів.

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

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

Правила такі:

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

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


2

TDD зовсім не обмежується тим, що традиційна спільнота тестування програмного забезпечення називає "тестуванням одиниць". Це дуже поширене непорозуміння є результатом нещасного перевантаження Кента Бека терміном "одиниця" під час опису його практики TDD. Те, що він мав на увазі під «одиничним тестом», було тестом, який проходить ізольовано. Це не залежить від інших тестів. Кожен тест повинен налаштувати необхідний стан та здійснити будь-яке очищення, коли це буде зроблено. Саме в цьому сенсі одиничне випробування в сенсі TDD є одиницею. Це самодостатнє. Він може запускатися сам по собі або він може бути запущений разом з будь-яким іншим тестом одиниці в будь-якому порядку.

Довідка : "Розробка тестових процесів за прикладом", Кент Бек

Кент Бек описує, що він має на увазі під «одиничним тестом» у главі 32 - Оволодіння TDD


1

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

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

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


1

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

Тож ні в TDD тести не завжди є одиничними тестами.

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

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


-1

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

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


1
Це невірно: залежно від програми та тесту (та мови) тести інтеграції в кінці можуть легко працювати менше ніж за 3 секунди. Цілком можливо запустити повний тестовий набір за дуже мало часу, навіть якщо він добре розроблений. Так що "не можна" досить сильно.
Джонатан У ролях

@jcast Я ніколи не бачив нічого іншого, що так швидко. Мої функціональні тести на попередньому проекті зайняли 30 секунд, і це швидко. Інтеграція ще довше. У моєму випадку нічого іншого не мало сенсу. Також одиничні тести є найшвидшими з усіх видів тестів - тому їх має сенс використовувати.
BЈоviћ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.