Якщо ваш тестовий код "пахне", це насправді має значення?


52

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

Наскільки занепокоєний я через надто погано сконструйовані ("смердючі") тести?


8
Наскільки важко виправити код, який ви завжди копіюєте?
JeffO

7
запах коду в тестах легко може бути показником прихованого запаху в решті коду - навіщо підходити до тестів так, ніби вони не є "справжніми" кодами?
HorusKol

Відповіді:


75

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

Ось кілька поширених запасів тестування блоку:

  • Крихкість : чи часто і несподівано ваші тести провалюються навіть на вигляд тривіальних або незв'язаних змін коду?
  • Стан витоку : чи ваші тести виходять з ладу по-різному залежно, наприклад, від того, який порядок вони виконуються?
  • Налаштування / відривчастий процес : Чи налаштовані / налаштовані блоки довгі та зростають довше? Вони виконують якусь ділову логіку?
  • Повільне виконання : чи потрібно тривати тривалий час ваші тести? Будь-який з ваших індивідуальних тестів на одиницю займає більше десятої частини секунди? (Так, я серйозно, десяту частину секунди.)
  • Тертя : Чи існуючі тести ускладнюють написання нових тестів? Чи трапляєтеся ви часто стикатися з несправностями тесту під час рефакторингу?

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

Ось, з іншого боку, є кілька хороших практик для одиничних тестів:

  • Швидкий, цілеспрямований зворотній зв'язок : ваші тести повинні швидко виявити збій і дати корисну інформацію щодо його причини.
  • Мінімізуйте відстань тестового коду : між тестом та кодом, який його реалізує, має бути чіткий та короткий шлях. Великі відстані створюють зайві довгі петлі зворотного зв'язку.
  • Тест на одну річ за раз : Одиничні тести повинні перевіряти лише одне. Якщо вам потрібно перевірити іншу річ, напишіть ще один тест.
  • Помилка - це тест, який ви забули написати : Що ви можете навчитися з цієї невдачі писати кращі, повніші тести в майбутньому?

2
"Одиничні випробування служать різному призначенню та мають різний набір напружень, які інформують їх дизайн". Наприклад, вони повинні ДАМПУВАТИ, не обов'язково ДУХИТИ.
Йорг W Міттаг

3
@ Йорг Погодився, але чи DAMP насправді щось означає? : D
Рейн Генріхс

5
@Rein: Описові та змістовні фрази. Також не зовсім ДУХА. Дивіться codehelter.wordpress.com/2011/04/07/…
Роберт Харві

+1. Я також не знав значення DAMP.
egarcia

2
@ironcode Якщо ви не можете працювати над однією системою ізольовано, не побоюючись порушити її інтеграцію з іншими системами, це пахне як щільне з'єднання для мене. Саме ця мета ідентифікує тестові запахи, як тривалість виконання: вони інформують вас про такі проблеми дизайну, як щільна муфта. Відповідь не повинна бути "О, тоді тестовий запах недійсний", він повинен бути "Що цей запах говорить мені про мій дизайн?" Тестові одиниці, що визначають зовнішній інтерфейс вашої системи, повинні бути достатніми, щоб повідомити, чи не змінюються ваші зміни інтеграцією зі споживачами.
Рейн Генріхс

67

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


17
+1 У той момент, коли ви починаєте ігнорувати невдалі тести, вони не додають ніякої цінності.

19

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

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


4
+1 ви повинні підтримувати тести, як і виробничий код
Hamish Smith

Ще одна дуже хороша книга на цю тему - тест Джерарда Мецароса "xUnit тестові зразки - тестовий код Refatcoring".
adrianboimvaser

7

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

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


5
+1: Не метушіться за тестовим кодом пристрою. Деякі найглуміші запитання пов'язані з тим, щоб зробити тестовий код модуля більш "надійним", щоб зміна програмування не порушила тест одиниці. Спритність. Одиничні випробування розроблені таким чином, щоб вони були крихкими. Добре, якщо вони менш надійні, ніж код програми, який вони розроблені для тестування.
С.Лотт

1
@ S.Lott Обидва згодні і не згодні з причин, що краще пояснені у моїй відповіді.
Рейн Генріхс

1
@Rein Henrichs: це набагато серйозніші запахи, ніж описано в питанні. "копіювати та вставляти" та "виглядати досить некрасиво" не здаються такими поганими, як запахи вашого опису, де тести недостовірні.
С.Лотт

1
@ S.Lott точно, я думаю, якщо ми будемо говорити про "одиничне тестування запахів", що важливо зробити це розрізнення. Кодові запахи в одиничних тестах часто ні. Вони написані для різних цілей, і напруженість, яка змушує їх пахнути в одному контексті, дуже сильно відрізняється в іншому.
Рейн Генріхс

2
@ S.Lott btw Це здається ідеальною можливістю скористатися значно занедбаною функцією чату :)
Rein Henrichs

6

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

Технічне обслуговування

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

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

Читабельність

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

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

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

Ви сказали:

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

Здається, що ви, безумовно, могли прочитати деякі технічні засоби тестування, такі як використання системи глузування, щоб зробити ваше життя набагато простішим. Я дуже настійно рекомендую The Art of Unit Testing , який охоплює вищезазначене та багато іншого. Мені це стало просвітницьким після довгого боротьби з погано написаними, нездійсненними, "смердючими" тестами. Це одна з найкращих інвестицій за час, яку я зробив цього року!


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

5

Два питання до вас:

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

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

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


5

Коли сміття почне пахнути, прийшов час вивезти його. Ваш тестовий код повинен бути таким же чистим, як і ваш виробничий код. Ви б показали це своїй матері?


3

Окрім інших відповідей тут.

Код низької якості в одиничних тестах не обмежується вашим набором тестових одиниць.

Однією з ролей, які заповнюються Тестуванням одиниць, є Документація.

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

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


3

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

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

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

Тож питання, яке ви ставите (з моєї точки зору), чи варто економити собі час або писати код, який витратить час?

На це питання можу лише сказати, наскільки важливий ваш час?

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


2

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


2

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

Залежно від складності тестової настройки код може бути складнішим. (httpcontext.current і жахливий монстр намагається точно створити помилкове, наприклад)

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


0

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

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

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