100% покриття коду - це мрія?


28

Чи можливо очікувати 100% покриття коду у важких веб-програмах jquery / backbonejs? Чи розумно відмовитися від спринту через те, що 100% покриття не буде досягнуто, коли фактичне покриття коду вагається приблизно від 92% до 95% у JavaScript / jquery?


7
"Збій зі спринту" звучить дивно зловісно ...
Доналі,

5
Це асимптота.
Роберт Харві

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

11
Все можливо. Справжнє питання полягає в тому, чи варто 100% покриття коду вартістю витрат часу та ресурсів.
JohnFx

5
Чому ви переживаєте з цього приводу, коли основне припущення - 100% (або будь-яке інше число) автоматичне тестове покриття магічним чином покращить ваш код - сама мрія про трубу?
Мейсон Уілер

Відповіді:


30

Він настільки ж реалістичний, як і нереальний.

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

Нереально
Ви починаєте з 0% покриття ...
Проект жахливий з багатьма, багатьма шляхами помилок, які важко відтворити або запустити.
Керівництво не бажає брати на себе зобов'язання / інвестувати, щоб переконатися, що покриття існує.

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

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


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

3
+1 для розміру проекту Розбиття на більш дрібні, багаторазові та тестовані компоненти дозволило нам самостійно отримати ~ 95% покриття. 100% покриття не потрібно. Інтеграційне тестування повинно покривати прогалини в одиниці тестування.
Апоорв Хурасія

5
@BryanOakley ... а також ваші тести можуть бути безглуздими або навіть нічого не перевіряти
David_001

5
@BryanOakley І навіть при 100% покритті гілок, можливо, певна комбінація гілок може спричинити проблеми. (Наприклад, два послідовних оператора IF можна розгалужувати на окремі тести та навколо них, але пропускати тест, який входить і в обидва . Повне охоплення гілки, але пропущений один шлях виконання)
Izkata

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

32

Хто тестує тести?

Це дуже наївно в кращому випадку і нереально навіть в теоретичному сенсі і непрактично в діловому розумінні.

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

Тестування кожного рядка коду не є хорошою метою

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

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

Проблема зупинки:

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

У 1936 році Алан Тьюрінг довів, що загальний алгоритм вирішення проблеми зупинки для всіх можливих пар програм-введення не може існувати. Ключовою частиною доказу було математичне визначення комп’ютера та програми, яке стало відомим як машина Тьюрінга; проблема зупинки не можна вирішити для машин Тьюрінга. Це один із перших прикладів вирішення проблеми.

Оскільки ви навіть не можете довести, що щось працює на 100%, навіщо робити це своєю метою?

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


7
це дійсно має бути прийнятою відповіддю. 100% покриття коду майже так само погано, як і 0%.
Рятхал

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

2
тож ви вважаєте, що написання тестових випадків для покриття простих getXXX()/setXXX()сортувальних конструкторів присвоєння об’єктів цінності - це корисне використання часу та ресурсів, вибачте, що це не так у дійсності, і надзвичайно наївна думка, що не вистачає досвіду реального світу для його резервування. Пам'ятайте, тестовий код все ще є кодом, який потрібно підтримувати. Чим менше коду ви пишете для вирішення проблеми, тим краще в кожному випадку .

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

17

У більшості випадків 100% охоплення кодом означає, що ви трохи «обдурили»:

  • Складні, часто мінливі частини системи (наприклад, gui) були переміщені до декларативних шаблонів або інших DSL.
  • Усі коди, що торкаються зовнішніх систем, були виділені або обробляються бібліотеками.
  • Те саме стосується будь-якої іншої залежності, особливо тієї, що потребує побічних ефектів.

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


Як переміщення речей до DSL обманює?
back2dos

2
@ back2dos - Хоча ви можете скасувати тест скажімо, ваші вбудовані сценарії python, ви, швидше за все, не перевіряєте свої шаблони html або ваш CSS, або не рахуєте рядки в них до оцінок покриття.
Дан Монего

12

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

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


9

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

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

Набагато важливіше, чи правильні тести? Чи точно вони відображають ваш бізнес та вимоги? Наявність кодового покриття просто для покриття коду не означає нічого, якщо все, що ви робите, - тестування неправильно або тестування неправильного коду. Незважаючи на те, що якщо ваші тести хороші, незадовільним є 92-95% покриття.


1
Тестування того, що трапляється, коли ви отримуєте дивні комбінації випадків помилок та відмов у відповіді, може бути винятково складним.
Дональні стипендіати

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

це співвідноситься unit testingз integration testingтестуванням коду, який ви не писали, є integrationтестуванням. Стек TCP знаходиться в ОС, ви не повинні тестувати це, ви повинні припустити, що його вже перевіряв хтось, хто його написав.

4

Я б сказав, якщо код не розроблений з конкретною метою, що дозволяє 100% охопити тест, 100% може бути недосяжним. Однією з причин є те, що якщо ви кодуєте захисно - що вам слід, - у вас іноді повинен бути код, який обробляє ситуації, які ви впевнені, що цього не повинно відбуватися або не може відбуватися, враховуючи ваші знання про систему. Захопити такий код тестами було б дуже важко за визначенням. Не мати такого коду може бути небезпечно - що робити, якщо ви помиляєтесь, і ця ситуація трапляється один раз із 256? Що робити, якщо в непов'язаному місці є зміна, яка робить неможливою річ? І т. Д. Тому 100% може бути досить важко досягти "природними" засобами - наприклад, якщо у вас є код, який виділяє пам'ять, і у вас є код, який перевіряє, чи не вийшов з ладу, якщо ви не знущаєтесь з менеджера пам'яті (що може бути непростим) і написати тест, який повертається "з пам'яті", покриття цього коду може бути важким. Для програми JS це може бути захисне кодування навколо можливих химер DOM у різних браузерах, можливі збої зовнішніх служб тощо.

Тому я б сказав, що слід прагнути бути максимально близьким до 100% і мати вагомі причини для дельти, але я б не бачив, щоб не отримати точно 100% як обов'язково провал. 95% може бути штрафом у великому проекті, залежно від того, які 5%.


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

2

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

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

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

Чи розумно відмовитися від спринту через те, що 100% покриття не виконується, коли фактичне покриття коду коливається приблизно 92% -95% в JavaScript / jquery?

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


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

@ still_dreaming_1, ти, здається, ти підтримав моє твердження і суперечив собі. Функції зменшення масштабів або зміни термінів є компромісом, кожен з яких може вплинути на вартість проекту та очікування зацікавлених сторін. Тестування застарілого коду, який раніше не був протестований повністю, є надзвичайно складним, оскільки ви повинні зрозуміти не тільки код, який він працює, але й наміри оригінального творця, а також написання тестів, що фіксують наявну поведінку попереднього коду, не обов'язково показувати що код працює повністю як належить.
S.Robins

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

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

1

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

Чи є якась особлива перешкода, з якою ви стикаєтесь, яка заважає вам потрапляти в останні кілька рядків? Якщо ні, якщо отримання від 95% до 100% покриття просте, то ви також можете зробити це. Оскільки ви тут питаєте, я припускаю, що є щось. Що це таке?


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

0

92% - це добре. Я відчуваю, що справжні питання:

  • 92% є "новою" нормою зараз? Якщо наступний спринт має 88% тестування, це буде нормально? Це часто початок відмови від тестових наборів.

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

  • Чи є план повернутися назад та заповнити пропущені тести?

  • Чому ви тестуєте? Схоже, фокус -% покриття рядків, а не функціональність


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

0

Мартін Фаулер пише у своєму блозі :I would be suspicious of anything like 100% - it would smell of someone writing tests to make the coverage numbers happy, but not thinking about what they are doing.

Однак є навіть стандарти, які передбачають 100% охоплення на рівні одиниць. Наприклад, це одна з вимог у стандартах європейської спільноти космічних польотів (ECSS, Європейське співробітництво з питань стандартизації космосу). Документ, зв'язаний тут , розповідає про цікаву історію проекту, який мав на меті досягти 100% тестового покриття у вже готовому програмному забезпеченні. Він заснований на nterviews з залученими інженерами, які розробили одиничні тести.

Деякі уроки:

  • 100% покриття незвичне, але досяжне
  • Іноді необхідне 100% покриття
  • 100% покриття приносить нові ризики
  • Не оптимізуйте для 100% -метричного
  • Розробіть належну стратегію для максимального охоплення
  • 100% покриття не є достатньою умовою для хорошої якості

0

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

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

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

Досягнення 100% покриття кодом - це неприродний вчинок. Для більшості людей змушення їх робити це було б формою катувань.

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

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

Ось кілька зусиль, щоб зробити кодування більш природним:

https://github.com/jcoplien/trygve

https://github.com/still-dreaming-1/PurposefulPhp

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


-2

Досягнення 100% нового коду має бути дуже досяжним, і якщо ви практикуєте TDD, ви, швидше за все, досягнете цього за замовчуванням, оскільки ви дуже свідомо пишете тести для кожного рядка виробничого коду.

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

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

Книга Майкла Пера " Ефективна робота зі спадщинним кодексом " була для нас неоціненною для розробки стратегій додавання тестів до нашого спадкового коду.


-3

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


Ой! Тож хтось засмучений, що я не відповів на проблему в площині її концепції; тестування - це марно… Мені все одно, чи популярно це. Це ніколи не вийде. Це не може. Про це знали найрозумніші комп'ютерні вчені (Dijkstra, Knuth, Hoare та ін.). Я думаю, якщо ти програміст JavaScript, що хаффує програмуванням eXtreme, то ти не можеш перейматися цими кривошипами. Бла, що завгодно, кому все одно ... пишіть хитромудрий код. Відходи CO ^ 2 під час ваших тестів. - Я маю на увазі, хто встигає більше сидіти і думати? Ми експортували це на комп’ютер.
veryfoolish

3
Питання позначено тегом "TDD". TDD - це скоріше інструмент дизайну та інструмент дослідження проблем, ніж тестовий, і кожен "тест" - це лише приклад того, як код поводитиметься в якомусь контексті, щоб люди могли прочитати та зрозуміти, що відбувається, а потім безпечно змінити його . Зроблений TDD, як правило, призводить до отримання більш чистого, простого у використанні коду, а виконання тестів просто перевіряє, чи є документація поточною. Більшість пакетів TDD навряд чи виловлюють помилок; це не те, для чого вони там. Я думаю, що вас принижують, оскільки ваша відповідь зраджує це нерозуміння, і я сподіваюся, що цей коментар допомагає в цьому.
Lunivore
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.