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


35

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

Підводячи підсумки:

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

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


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

1
@Robert Harvey - Погодився - мені було б цікаво переглянути список цих об'єктів.
Джефф Левін

18
Що стосується першої точки - ви, як правило, недоліком одиничних тестів є те, що вони не працюють, коли ви їх не використовуєте. Можна сказати те саме про будь-яку іншу практику. Крім того, ваше використання пасивного голосу перекриває те, що хтось активно коментує одиничні тести. Отож, здається, у вас немає виплат у розробників у команді, це вже інша проблема.
ЖакБ


Відповіді:


62

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

Одиничні тести не є по суті поганими. Але вони часто перевіряють деталі реалізації, а не потік вводу / виводу. Ви закінчуєте цілком безглузді тести, коли це відбувається. Моє власне правило полягає в тому, що хороший одиничний тест говорить про те, що ти просто щось зламав; погане тестування просто говорить про те, що ви просто щось змінили.

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

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

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

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


13
Це, це, сто разів це. Це чудова річ у розробці тестових програм. Спочатку написання тестів допоможе вам написати тести, які не тестують деталі вашої реалізації, а передбачувану поведінку, яку ви намагалися реалізувати.
wirrbel

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

2
@DocBrown: Дійсно, ні. Що я мав на увазі, це так часто робиться неправильно, що колега ОП має це в більшості випадків правильно - або, принаймні, у всіх випадках, коли я коли-небудь стикався в одержимих компаніями підрозділах тестів.
Денис де Бернарді

3
@DenisdeBernardy: моя думка: все, що ви написали, це, безумовно, правильно з великою кількістю мудрості від практики, але я пропускаю висновок, що це означає для справи ОП з його колегою, в контексті пропозиції "інтеграційних тестів як краща альтернатива ".
Док Браун

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

38

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

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

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

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


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

+1 Для "ви повинні працювати над своїм визначенням зробленого". Добре сказано!
Андрес Ф.

14

Я не знаю, що я приймаю аргументи вашого колеги.

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

Є й інші, більш переконливі аргументи проти одиничних тестів. Ну, не зовсім проти них. Почніть з тестування, спричиненого випробуванням DHH на дизайні . Він веселий письменник, тому читайте його. Що я взяв із цього:

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

Якщо ви хочете отримати нюанси та філософські, є багато чудових ресурсів:


+1 для цієї статті, може бути кращою відповіддю на випадок ОП, ніж все те, що ми можемо написати тут.
Doc Brown

+1 для пункту №1 про те, що лінь є приводом. Я не можу підкреслити, наскільки це страшно. Я був там. Останнім часом, власне.
Грег Бургхардт

3
Причина 1 не є виною одиничних тестів, але це все ще є причиною проти одиничних тестів.
користувач253751

Прочитавши статтю DHH, переконайтеся, що ви подивіться відео, де він обговорював цю тему з Кентом Беком та Мартіном Фаулером (вони є на youtube) - багато людей, здається, отримують більш екстремальну версію своєї точки зору, ніж він задумав, і він цілком уточнює це в цих дискусіях.
Жуль

6

Коли відбуваються значні зміни коду (новий набір POJO, основні рефакторинг додатків тощо), одиничні тести, як правило, коментуються, а не переробляються.

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


4

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

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


3

Коли відбуваються значні зміни коду (новий набір POJO, основні рефакторинг додатків тощо), одиничні тести, як правило, коментуються, а не переробляються.

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

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

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

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

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

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

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

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

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


3

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

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

Кожен метод тестування буде неповним. Навіть якщо ви отримаєте 100% охоплення деякими показниками, ви все одно не переглядаєте практично кожен можливий набір вхідних даних. Отже, не думайте, що одиничні тести є магічними.

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

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

Одиничні тести - це інструмент у панелі інструментів. Вони там, щоб служити вам, а не навпаки. Не забудьте вийти з них хоча б стільки, скільки ви вкладете.


3

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

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

Посилаючись на пункти, зроблені вашим другом:

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

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

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


2

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

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

Однак: В першу чергу є (невелика) вартість часу на написання тестів.

Отже: Якщо проект досить короткий і не потребує постійного обслуговування / оновлень, можливо, вартість написання тестів переважає їх переваги.


+1 за спробу серйозно відповісти на поставлене запитання.
RubberDuck

2
Вартість одиничного тесту, безумовно, не мала. Хороші одиничні тести зазвичай вимагають більше часу для написання, ніж те, що вони тестують. Більшу частину часу переваги перевищують витрати.
AK_

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

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