Чи потрібно тримати тести на прості (автономні) функції?


36

Врахуйте це:

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

Припустимо, ви пишете різні тести на вищевказану функцію і доводить собі та оточуючим, що "це працює".

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


32
Чи не правда для кожної функції, що якщо ви не зміните свій код, якщо він працював вчора, він буде працювати і завтра? Справа в тому , що програмне забезпечення буде змінено.
5gon12eder

3
Тому що ніхто ніколи не буде писати override_function('pow', '$a,$b', 'return $a * $b;');з розумом ... або намагатися переписати його для обробки складних чисел.

8
Отже ... гм ... що "зарекомендував себе як безкоштовний код" ... у ньому є помилка .

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

6
Крім того, ця функція є чудовим кандидатом на зміну форми Хорнера, (($a*$x + $b)*$x + $c)*$x + $dщо легко помилитися, але часто значно швидше. Тільки тому, що ти думаєш, що це не зміниться, це не означає, що воно не буде.
Майкл Андерсон

Відповіді:


78

Регресійне тестування

Вся справа в регресійному тестуванні .

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

Відволікаючись, він перевертає дві константи.

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

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

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

Побічний ефект ...

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

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

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

Зміни вимог

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

Чому все це клопоту? Навіщо видаляти тести, щоб потім їх додати? Ви могли б утримати їх в першу чергу.


Педантична примітка: ніщо не є ризиком. ;)
jpmc26

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

Ще одна педантична примітка: Деякі "магічні" цифри насправді добре, а заміна їх константами - погана ідея.
Дедуплікатор

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

@jwenting: Просто додав цю замітку, тому що MainMa написала, що "нічого поганого в проведенні цієї зміни" немає.
Дедуплікатор

45

Тому що нічого не так просто, що не може бути помилок.

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

За винятком помилок ...

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

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


Додаток:

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

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

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


Є альтернативне рішення: перехід на нединамічні, слабкі мови. Юніт - тести, як правило , обхідний шлях для недостатньо сильного часу компіляції перевірки і деякі мови є свого роду благо в цьому en.wikipedia.org/wiki/Agda_(programming_language)
Den

21

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

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

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


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

@Kapol: не аргумент, нарада, щоб визначити, на що можна піти, а на яких можна зупинитися, і за якими критеріями слід прийняти рішення, а також де документувати критерії та хто підписує остаточне рішення ...
jmoreno

12

Все сказане в інших відповідях правильне, але я додам ще одну.

Документація

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

Це може полегшити кров’янисті помилки і зменшити плутанину.

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

Для прикладу того, наскільки корисною може бути документація, подивіться на вступ Жасмін: http://jasmine.github.io/edge/introduction.html Дайте йому кілька секунд для завантаження, а потім прокрутіть донизу. Ви побачите весь API Жасмін, задокументований як вихідний тестовий вихід.

[Оновлення на основі зворотного зв’язку від @Warbo] Тести гарантовано є актуальними, оскільки, якщо їх немає, вони вийдуть з ладу, що, як правило, спричинить збій у побудові, якщо використовується CI. Зовнішня документація змінюється незалежно від коду, і тому не обов'язково актуальна.


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

Я хотів би додати, що деякі мови, як D і Rust, інтегрують свою генерацію документації зі своїм тестуванням одиниць, тож ви можете мати один і той же фрагмент коду, як компілювати в тест одиниці, так і вставити в документацію HTML
Idan Arye

2

Перевірка реальності

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

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

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

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

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


4
У цьому випадку вже був тест, тому питання полягає не в тому, чи писати їх, а в тому, чи зафіксувати їх та запустити їх з кожною збіркою чи випуском чи будь-яким графіком для виконання всіх тестів.
Paŭlo Ebermann

0

Так, тримати тести, тримати їх та тримати їх.

Підрозділи тестів існують, щоб захистити вас (та інших) від себе (і себе).

Чому зберігання тестів є гарною ідеєю;

  • Обґрунтуйте функціональність попередніх вимог на тлі нових вимог та додаткових функцій
  • Перевірте правильність вправ на рефакторинг
  • Внутрішня документація - саме так очікується використання коду
  • Регресійне тестування, все змінюється
    • Чи зміни порушують старий код?
    • Чи потребують змін додаткові запити на зміни чи оновлення поточних функцій чи коду?
  • Враховуючи, що тести вже написані, зберігайте їх; час і гроші, які вже витрачені, зменшать витрати на технічне обслуговування далі вниз

2
Схоже, це не пропонує нічого істотного порівняно з іншими наданими відповідями.

1
Виникла проблема з її розміщенням раніше, але в ретроспективі це приємне резюме. Я його зніму.
Найлл

-1

Документація розробника

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

Документація користувача

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

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