TDD: Я правильно це роблю?


14

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

Що я роблю:

  1. Придумайте потрібний мені новий метод.
  2. Створіть тест для цього методу.
  3. Тест на провал.
  4. Метод запису.
  5. Пройти тест.
  6. Рефакторний метод.
  7. Повторіть.

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

EDIT

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


5
Ви вже робите це набагато краще, ніж досвідчені професіонали, які кажуть, що все тестують (але не роблять).
янніс

Те, що ви описуєте, не є Духом TDD.

1
Ви можете заглянути в ATDD або BDD.
дієтабудда

Можливо, почніть вище - придумайте потрібний вам новий модуль .

Відповіді:


16

Те, що ви описуєте як робочий процес, на мій погляд, не є Духом TDD.

Конспект книги Кента Бекса про Amazon говорить:

Простіше кажучи, тестова розробка призначена для усунення страху при розробці додатків.Хоча деякий страх є здоровим (його часто розглядають як совість, яка закликає програмістів "бути обережними!"), Автор вважає, що побічні продукти страху включають орієнтовних, бурхливих та некомунікативних програмістів, які не здатні сприймати конструктивну критику. Коли програмуючі команди купують TDD, вони одразу бачать позитивні результати. Вони усувають страх, пов’язаний зі своєю роботою, і краще готові вирішувати складні виклики, які стоять перед ними. TDD усуває орієнтовні риси, вчить програмістів спілкуватися, і це спонукає членів команди шукати критику. Однак, навіть автор визнає, що бурхливість повинна бути розроблена індивідуально! Коротше кажучи, передумова TDD полягає в тому, що код слід постійно перевіряти і реконструювати.

Практичний TDD

Офіційне автоматизоване тестування, особливо тестування підрозділів кожного методу кожного класу, є таким же поганим антидіаграмою і нічого не тестує. Має бути баланс. Ви пишете одиничні тести для кожного setXXX/getXXXметоду, вони також є методами!

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

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

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

Вам дуже важко буде знайти багато професійних магазинів, які працюють і таким чином. Це просто не має сенсу витрачати гроші на тестування речей, які за будь-яких практичних цілей ніколи не зміниться після того, як простий тест на дим буде сформований. Написання формальних автоматизованих одиниць тестів для .getXXX/.setXXXметодів - це яскравий приклад цього, повного марнування часу.

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

- Едсгер В. Джикстра . (Написано у 1988 році, тому зараз ближче до 4,5 десятиліть.)

Дивіться також цю відповідь .


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

@kevincline Більшість часу setXXX/getXXXвзагалі не потрібна :)
Фішка

1
Коли ви запам'ятаєте цей тривіальний getXXX і помилитеся, або введете ледачу завантаження у ваш getXXX і помилитеся, то ви дізнаєтесь, що іноді ви дійсно хочете протестувати своїх дітлахів.
Френк Ширар

13

Ви дуже близькі. Спробуйте подумати цим дещо іншим способом.

  1. Подумайте про нову мені поведінку.
  2. Створіть тест на таку поведінку.
  3. Тест на провал.
  4. Написати новий або розширити існуючий метод.
  5. Пройти тест.
  6. Код рефактора.
  7. Повторіть.

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

Також пам’ятайте три правила ТДД дядька Боба .

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

1
@Zexanima: Ти робишся краще, ніж більшість із нас після року. Просто намагаюся вказати на наступний крок.
пдр

2
Я думаю, що ці 3 правила, на які ви посилаєтесь; настільки ідилічні, як вони можуть звучати, є винятково догматичними і дуже нереально жорсткими у 99% усіх виробничих цехів, з якими хто завгодно зіткнеться.

1
@FrankShearar або це можна розглядати як непрактичне блукання фундаменталістського екстремізму та оптово знехтування. Я працював у магазинах, які мали таке догматичне ставлення, вони сприйняли догматику буквально і пропустили суть; написання тестів, які не перевіряли жодного фактичного коду практично, і закінчували лише тестування фреймворків Mocking and Dependency Injection, здатних переплутати те, що було в кращому випадку важливим.

1
@pdr Дух чогось діаметрально протилежний догматичній формалізованій канонізації цієї речі. Одна справа мати філософію, а інша - скручувати її в релігію . TDD більше, ніж не розмовляють у чорно-білих догматичних релігійних термінах. Ці 3 правила звучать догматично і релігійно в презентації, і те, що чується - це мантра випробувань, випробувань, випробувань для когось, як ОП, вони приймають їх буквально, і це приносить більше шкоди, ніж користі. Я протидіяв Френку, що поляризаційні твердження можуть принести більше шкоди, ніж користі.

2
Моя думка полягала в тому, що догматизм походить від сліпого прийняття чогось як євангелії . Візьміть заяву про поляризацію, спробуйте, вимусьте вас вийти із зони комфорту. Ви не можете оцінити компроміси, що беруть участь у TDD, якщо ви не спробуєте екстремальний підхід "3-х балів" або "нічого", оскільки у вас не буде даних .
Френк Ширар

5

Кілька речей додати до відповідей інших:

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

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

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

  4. Ви запитали про тестування коду GUI. Знайдіть схеми "Скромний діалог" та "MVVM". Ідея цих обох полягає в тому, що ви створюєте набір класів "перегляду моделі", які насправді не мають логіки, що відповідає інтерфейсу. Однак у цих класах буде вся бізнес-логіка, яка зазвичай є частиною вашого інтерфейсу, і ці класи повинні бути перевірені на 100%. Що залишилося - це дуже тонка оболонка інтерфейсу користувача, і так, зазвичай ця оболонка залишається без тестового покриття, але в цей момент вона майже не має логіки.

  5. Якщо у вас є значна частина існуючого коду, як мало хто запропонував, вам не слід додавати одиничні тести абсолютно скрізь. Це займе вас назавжди, і ви не отримаєте користі від додавання одиничних тестів до 80% класів, які є стабільними і не зміняться в найближчому (або не такому найближчому) майбутньому. Однак для нової роботи я вважаю, що використання TDD-розробки з ВСЕМ кодом є надзвичайно вигідним. Ви не тільки закінчуєте набір з автоматизованими тестами, коли закінчите, але фактична розробка має величезні переваги:

    • Розглядаючи можливість перевірки, ви напишете код, який є менш сполученим та модульним
    • Розглядаючи свій державний контракт перед чим-небудь іншим, ви отримаєте публічні інтерфейси, які набагато чистіші
    • Під час написання коду перевірка нової функціональності займає мілісекунди порівняно із запуском всієї програми та спробою примусити виконання до правильного шляху. Моя команда все ще випускає код обробки помилок, який навіть не був виконаний НАЙКІЛЬКО тому, що вони не змогли встановити правильний набір умов для того, щоб статися. Дивовижно, скільки часу ми витрачаємо, коли згодом у КА ці умови трапляються. І так, багато цього коду - це те, що хтось вважав би «не місцем для великих змін у майбутньому, як тільки буде проведено тестування на дим».

1

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

У той час як ви можете надмірно перевірити свій код, зазвичай це відбувається, коли хтось хоче перевірити всі можливі перестановки входів, що не зовсім схоже на те, що ви робите. Наприклад, якщо у вас є метод, який приймає характер, ви пишете тест на кожне можливе значення, яке можна було б ввести? Це було б місце, де ви могли б переоцінити, ІМО.


Ах, гаразд. Це не те, що я роблю. Я зазвичай закінчуюсь думкою про іншу ситуацію, і я можу перевірити свої методи способами вниз, після того як я вже зробив їх початковий тест. Я просто переконався, що ці «зайві» тести варто зробити, або якщо це було над цим робити.
cgasser

Якщо ви працюєте досить невеликими кроками, зазвичай ви можете бути впевнені, що ваш тест справді працює. Іншими словами, тест на тест (з правильної причини!) Сам по собі тестує тест. Але рівень "достатньо впевненого" не буде таким високим, як код, який перевіряється.
Френк Ширар

1

Як правило, ти робиш це правильно.

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

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


Я теж писав тести для геттерів та сетерів, тому дякую за цю пораду. Це врятує мене від непотрібної роботи.
cgasser

"Деякі методи не потрібно чітко перевіряти (тобто прості геттери та сетери)" - Ви ніколи не копіювали / вставляли геттера та сеттера і не забували змінити ім'я поля за ним? Справа в простому коді полягає в тому, що він вимагає простих тестів - скільки часу ви дійсно економите?
пдр

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

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

0

Моя думка щодо TDD полягає в тому, що інструментарій створив світ розробників стилів "точка і натискання". Тільки тому, що інструменти створюють пробну заглушку для кожного методу, не означає, що ви повинні писати тести для кожного методу. Деякі люди «перейменовують» TDD як BDD (розвиток, орієнтований на поведінку), де тести є значно більш крупними і мають на меті перевірити поведінку класу, а не кожен чудо-маленький метод.

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

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

Є кілька хороших посилань праворуч про BDD v TDD. Перевірте їх.


0

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

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


0

Я вважаю, що ви перебільшуєте.

Я займаюся TDD багато років, і за моїм досвідом, коли TDD виконується ефективно, ви отримуєте дві основні переваги:

  • Забезпечуйте швидкий зворотний зв'язок
  • Увімкнути рефакторинг

Забезпечуйте швидкий зворотний зв'язок

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

Увімкнути рефакторинг

Якщо у вас хороший набір тестів, ви можете сміливо переробляти, отримуючи нові уявлення про те, як повинна бути спроектована система.

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

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

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

Або, як каже Іван Купер у цій презентації (я цитую її з пам’яті, тому, можливо, це неправильно не цитується):

Вашою причиною для написання нового тесту має бути додавання нової поведінки, а не додавання нового класу


-2

Ви повинні перевірити кожен публічний метод.

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

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

EDIT: Відповідь pdr набагато повніша, ніж моя.

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