Які недоліки написання коду перед тестуванням одиничних тестів?


33

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

Оскільки я бачу чимало рекомендацій почати писати тести, а потім перейти до кодування, які недоліки, якщо я це роблю іншим способом - написати код, а потім одиничні тести?


7
+1, щоб запитати, чому певна практика є "найкращою практикою", перш ніж
прийняти

Відповіді:


37

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

Вимоги (тести), розроблені після коду на основі коду, позбавляють вас такої впевненості, цієї впевненості.


+1 - відмінна очка та взяті бали! Дякуємо за вашу думку!
k25

7
Тести! = Вимоги. І тести, і код повинні випливати з вимог.
Барт ван Іґен Шенау

2
@Bart van Ingen Schenau: Сила TDD саме в тому, що тестує ARE вимоги. Більше того, вони відповідають вимогам.
mouviciel

1
@Bart: Тестові підрозділи часто занадто детальні для (високого рівня) вимог замовника, але ідея, безумовно, справедлива, особливо якщо ми також враховуємо тести вищого рівня, такі як автоматизовані тести приймання, які після написання повинні бути остаточними вимогами. У цьому полягає суть "спритного тестування на прийняття".
Мартін Вікман

3
TDD - це не тестування, це специфікація. Тести, побудовані на підході до TDD, є засобом комунікації між розробником та замовником для узгодження того, який продукт слід виготовити.
mouviciel

18

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

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


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

2
Але що робити, якщо тест пройде? Тест може пройти, оскільки він фактично не використовує код, що цікавить; насправді це не може статися під TDD, оскільки тест повинен спочатку провалитись, і так - якщо цього не відбувається, ви не переходите до кроку 2, поки не виправите це. Отже, в тесті останній є режим відмови, який спочатку не існує в тесті.
Карл Манастер

@Carl Manaster - Так, у вас дійсна точка. Після того, як я напишу код, я чудово знаю вимоги, і тому мій тестовий випадок буде правильним (в ідеалі). Якщо мій тест пройде, я б сказав, що код правильний, якщо тест не вдасться, я буду дотримуватися сказаного. Але я на 100% згоден, що у вас є дійсна точка.
k25

@ k25: Справа в тому, що якщо ваш тестовий випадок пройде, ви все ще не знаєте, чи правильний код чи ні. Тестовий випадок може бути неправильним.
Анон.

@Anon. - так, ви маєте рацію, я також буду враховувати цю справу.
k25

12

Насправді люди завішуються на TDD - це тестування, хоча вони забувають про інші дві літери в абревіатурі. Щось тут можна прочитати: TDD без T або TDD - це не про тестування .

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

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

Особисто я пізнав себе принципів ТВОРНОГО, не знаючи, що написано таке. Це тому, що написання одиничних тестів змусило мене переписати класи, щоб вони не стали надмірно складними для тестування. Це призвело до таких речей, як:

  • Мені довелося перенести функціонал, який або не мав сенсу, або перебував у приватних методах, до окремих класів, щоб я міг перевірити їх окремо. (Принцип єдиної відповідальності).
  • Мені довелося уникати великих структур успадкування та розширювати реалізацію замість цього складу (видно в принципі Open-Closed).
  • Мені потрібно було бути розумним щодо спадкування, я використовував абстрактні класи, коли бачив загальний код, яким можна ділитися, і використовував методи заглушки (Принцип заміни Ліскова).
  • Мені довелося писати інтерфейси та абстрактні класи, щоб я міг перевірити заняття в окремому режимі. Що ненароком приводить вас до написання макетних об’єктів. (Принцип поділу інтерфейсу)
  • Оскільки я написав багато інтерфейсів та абстрактних класів, я почав оголошувати змінні та параметри для використання загального типу (принцип інверсії залежності).

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


1
+1 для SOLID природно виникає у вас, коли ви думаєте про розробку програмного забезпечення.
ocodo

+1 (насправді я хотів дати +10, але не можу). Точно мої думки - ти перелік балів був надзвичайно хорошим. Це одна з причин, що я задав це питання. Я відчув, що занять стало набагато більше, коли я почав писати одиничні тести після написання коду. Але я хотів побачити переваги / недоліки обох сторін, дякую за вашу думку!
k25

10

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


4

Якщо ви пишете свої тести спочатку, це дає ще один шанс подумати над своїм дизайном, перш ніж цей дизайн буде «залитий каменем».

Наприклад, ви можете подумати, що вам потрібен метод, який приймає певний набір параметрів. І якщо ви спочатку написали код, ви написали би його таким чином і зробили тест відповідно до заданих параметрів. Але якщо ви спочатку пишете тест, ви можете подумати, "зачекайте хвилину, я б не хотів використовувати цей параметр у коді основного рядка, тому, можливо, я повинен змінити API"


+1 за перший бал. Але, не дійшовши до рівня параметрів, що робити, якщо дизайн обговорювались з іншими та приймали?
k25

@ k25 - якщо щось важко використовувати за задумом, воно потребує більше роздумів. Іноді - дуже рідко - це просто важке завдання. Але частіше це можна звести до більш простих завдань. У мене немає посилання, але або Гослінг, або Гетц зробили інтерв'ю щодо дизайну API кілька років тому ... варто Гуглінг.
Анон

звичайно, дякую за покажчики, я обов’язково
зазирнуму

2

Оскільки я бачу багато рекомендацій, щоб почати писати тести, а потім перейти до кодування,

Для цього є справді вагома причина.

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

Якщо ви скажете «спочатку написати тести», люди, принаймні, можуть спробувати зробити все правильно.

які недоліки, якщо я це роблю іншим способом - написати код, а потім одиничні тести?

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

Однак це лише "зазвичай". Деякі люди розробляють конструкції та тести паралельно. Деякі люди ставлять тестовий код на місце і пишуть тести без переробки.

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

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

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

Правила висловлюються дуже рішуче з причини.

Те, що ви робите, - це ваша власна проблема.


2

Перш ніж написати тест, це змушує задуматися

  • Як перевірити код
  • інтерфейс коду повинен бути перевіреним

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

але TDD розгортається на тести прийняття, а не просто тестові одиниці, і тоді інтерфейс стає нетривіальним.


1

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

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

Книги: Бек, К. Тестова розробка за прикладом

Хороший приклад: http://jamesshore.com/Blog/Lets-Play/


+1 - приємні бали (особливо 1-го) та дякую за посилання!
k25

0

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

Спочатку написання коду, а потім тест залишає відкритим питання про те, чи показав би тест чесний збій.

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

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