Написання тестів за існуючим кодом


68

Припустимо, одна мала порівняно велику програму (скажімо, 900k SLOC у C #), всі коментували / документували ретельно, добре організовано та працювали добре. Вся база коду була написана одним старшим розробником, який більше не працює з компанією. Весь код перевіряється таким, як є, і IoC використовується протягом усього періоду - за винятком якоїсь дивної причини, вони не писали жодних одиничних тестів. Тепер ваша компанія хоче розгалужувати код і хоче додавати одиничні тести, щоб виявити, коли зміни порушують основну функціональність.

  • Чи додавання тестів є гарною ідеєю?
  • Якщо так, то як би взагалі почати щось подібне?

EDIT

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

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

ВИСНОВОК

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


10
Додавання тестів не порушить існуючий код.
Ден Пішельман

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

8
@MichaelT Тепер, коли ви це згадуєте, я думаю, що я бачив один-два з них. Мій коментар повинен був читати "Додавання тестів зазвичай не порушує існуючий код". Спасибі
Ден Пішельман

3
Пишіть лише тести навколо речей, які ви збираєтесь змінити або змінити.
Стівен Еверс

3
Перевірте книгу "Ефективна робота зі застарілим кодом": amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/… , Michael Feathers пропонує написати тести, перш ніж змінювати будь-який застарілий код.
Скараб

Відповіді:


68

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

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

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

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

Також див .


11
Але навіть без TDD, одиничні тести корисні при рефакторингу.
пдр

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

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

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

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

35

Так, додавання тестів, безумовно, хороша ідея.

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

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

Я б порекомендував книгу Майкла Пірса « Ефективна робота зі спадщинним кодексом» для отримання гарних детальних порад.


10
+1. Якщо ви пишете тести на основі документації, ви виявите всі розбіжності між робочим кодом та документацією, і це неоціненно.
Карл Манастер

1
Ще одна причина додавання тестів: коли буде виявлена ​​помилка, ви можете легко додати тестовий випадок для подальшого тесту регресії.

Ця стратегія в основному викладена в (безкоштовному) онлайн-курсі edX CS169.2x у розділі про застарілий код. Як кажуть викладачі: "Встановлення основної істини за допомогою тестів на характеристики" у розділі 9 книги: beta.saasbook.info/table-of-contents
FGM

21

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

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

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

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


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

8

Чи додавання тестів є гарною ідеєю?

Абсолютно, хоча мені трохи важко повірити, що код чистий і працює добре, використовуючи сучасні методи і просто не має одиничних тестів. Ви впевнені, що не сидите в окремому рішенні?

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

Якщо так, то як би взагалі почати щось подібне?

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

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


7
"Ви впевнені, що не сидите в окремому рішенні?" чудове питання. Я сподіваюся, що ОП цього не помічає.
Ден Пішельман

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

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

3

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

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


Чи дійсно ви додали б пробні тести до програми, яка працює добре (говорить ОП)?
MarkJ

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

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

@DanPichelman: Погодився, але це зовсім не повинно перешкоджати написанню тестів.
Бернард

Якщо нічого іншого, це вказувало б на те, що код не був написаний захисно.
Роббі Ді

3

Гаразд, я буду висловлю протилежну думку ...

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

У всякому разі, я б не додавав жодних одиничних тестів.

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


2

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

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

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

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