Сім принципів тестування програм
Інші технології верифікації, такі як статичний аналіз, перевірка на моделі і випробування, мають величезний потенціал, але жодна з них не є настільки досконалою, щоб замінити тести як домінуючу технологію. Тому необхідно зрозуміти, яка сфера дії і обмеження тестування і як правильно його виконувати.
Всі викладені в статті принципи сформульовані на основі практичного досвіду тестування програмного забезпечення та досліджень, що передували розробку автоматизованих інструментальних засобів, таких як AutoTest (se.inf.ethz.ch/research/autotest).
визначення тестування
Тестування як метод верифікації - це парадокс. Тестування програми для того, щоб перевірити її якість, теоретично рівносильно утикання шпильок в ляльку, причому дуже маленьких шпильок в дуже велику ляльку. Дозволити цей парадокс можна, визначивши реалістичні очікування.
Занадто часто тестування в літературі з програмної інженерії надають великого значення, що, власне, і відображено у визначенні, даному в Wikipedia: «Тестування програмного забезпечення - це процес оцінки якості комп'ютерних програм. Тестування - це практичне технічне вивчення, проведене для того, щоб надати зацікавленим сторонам інформацію про якість продукту або сервісу з урахуванням контексту, в якому, як передбачається, він буде працювати ». Насправді, тестування програми мало що говорить про її якість, оскільки 10 чи навіть 10 млн тестів - це лише крапля в океані всіх можливих випадків.
Безумовно, зв'язок між тестами і якістю програм існує, але вона досить слабка? - успішний тест дозволяє оцінити якість лише в тому випадку, якщо перш він не був пройдений. Тоді це свідчить про відсутність невдачі і, як правило, - відсутність самої помилки *.
Якщо систематично відстежувати невдачі і помилки, то їх реєстрація може дати уявлення про те, скільки ще помилок залишилося. Якщо останні три тижні при роботі тестів було виявлено 550, 540 і 530 помилок, то тенденція обнадіює, але малоймовірно, що при наступному тестуванні буде виявлено жодної помилки або всього 100 таких. (Математичні моделі надійності дозволяють оцінити це більш точно і достовірно, якщо реалізований ефективний процес довгострокової збірки даних.)
Єдина безперечна зв'язок - це негативна зв'язок, або, в термінології Поппера, «фальсифікація». Невдалий тест говорить про недостатню якість програми. Крім того, якщо раніше тест проходив, а тепер немає, то це свідчення регресії, яке вказує на можливі проблеми якості в програмі і в процесі розробки. Найвідоміше висловлення про тестування разюче точно це описує.
«Тестування програм, - відзначав Едсгер Дейкстра, - можна використовувати для того, щоб показати наявність помилок і ніколи - для того щоб показати їх відсутність!» Далеко не всі (Дейкстра, ймовірно, на це й не сподівався) розуміють, що для тестувальників це означає найкращу можливість для самореклами. Безумовно, будь-яка методика, що дозволяє знаходити помилки, вкрай важлива для «зацікавлених осіб», від менеджерів до розробників і користувачів. Ми повинні сприймати цю максиму не як якесь звинувачення, а як визначення тестування. Звичайно, це не настільки амбітно звучить, як «надання інформації про якість», але зате більш реалістично і практично.
Принцип 1. Визначення. Для того щоб протестувати програму, потрібно спробувати змусити її працювати невірно.
В силу цього принципу процес тестування знаходить мета: його єдине завдання - знайти помилки, ініціюючи невдале виконання. Будь-яке умовивід з приводу якості відноситься до області гарантії якості, але ніяк не до області тестування. Це визначення також нагадує нам, що тестування, на відміну від налагодження, не пов'язане з виправленням помилок, - воно пов'язане тільки з їх пошуком.
Тестування і специфікації
При створенні програм, спирається на тестування (test-driven) і отримав популярність завдяки методам «швидкої» (agile) розробки, тести ставлять на перше місце, але іноді вважають, що вони можуть замінити специфікації. Не можуть. Тести, навіть якщо їх мільйон, - це лише приклади; в них відсутній абстракція, яку може дати тільки специфікація.
Принцип 2. Тести або специфікації. Тести не замінюють специфікації.
Небезпека помилки, що тести можуть виступати в ролі специфікацій, була продемонстрована цілим рядом програмних катастроф, які сталися тільки тому, що ніхто не подумав про винятковому випадку. Незважаючи на те, що в специфікаціях теж можуть бути втрачені не врахували якісь випадки, по крайней мере, в них робиться спроба нікого узагальнення. Зокрема, специфікації можуть використовуватися для генерації тестів, навіть автоматично (як у випадку тестування, що спирається на моделі); але зворотне без втручання людини неможливо.
регресивний тестування
Особливістю тестування, якщо судити по практиці створення програмного забезпечення, є сумна схильність до появи вже виправлених помилок. Старі голови у гідри, як би глибоко вони не були відсічені, виростають знову. Це явище відоме як регресія і змушує використовувати регресивний тестування, тобто перевірку того, що виправлене раніше і раніше працює. Як наслідок, ви завжди повинні пам'ятати про помилку, яку вже колись виявили.
Принцип 3. Регресивне тестування. Будь-яке невдале виконання повинно породжувати тестовий випадок, який назавжди стає частиною тестового пакета даного проекту.
Цей принцип стосується всіх помилок, що виникли під час розробки та тестування. Звідси випливає необхідність в інструментарії, що дозволяє перетворювати невдале виконання до відтвореного тестовий випадок, і недавно такий інструментарій з'явився: Contract-Driven Development, ReCrash, JCrasher.
Пророцтва
Виконання тесту корисно тільки в тому випадку, якщо ви можете однозначно визначити, чи пройшов він. Критерій називається передбаченням тесту. Якщо у вас є кілька десятків або навіть сотень тестів, то ви в змозі перевірити їх результати окремо, проте зі збільшенням їх кількості це стає все менш імовірним. Дане завдання вимагає автоматизації.
Принцип 4. Використання пророкувань. Визначення успіху або невдачі тестів повинно відбуватися автоматично.
Це формулювання залишає відкритим питання про форму таких передбачень. Найчастіше передбачення специфицируются окремо. У дослідженнях, таких як наше, вони вбудовані, оскільки аналізоване програмне забезпечення вже включає в себе контракти, згідно з якими тести використовуються як передбачення.
Принцип 4 (варіант). Контракти як передбачення. Пророцтва повинні бути частиною тексту програми як контракти. Успіх чи невдача тесту повинні визначатися автоматично, причому в рамках цього процесу необхідно вести моніторинг виконання контракту під час роботи програми.
Цей принцип деталізує попередній, в силу чого ті, хто не використовує контракти, можуть дотримуватися більш простий його форми.
Тестові випадки, перевіряються вручну і автоматично
Багато тестові випадки перевіряються вручну. Тестери продумують цікаві сценарії виконання і готують відповідні тести. До цієї категорії можна додати тести, отримані відповідно до принципу 3 як результат некоректного виконання, їх спочатку не передбачалася використовувати при тестуванні. Зараз все частіше можна доповнити ці дві категорії автоматичними тестовими випадками, отриманими з специфікацій за допомогою генератора автоматичних тестів. Процес, обмежений тестами, виконуваними вручну, не в повній мірі використовує можливості сучасних комп'ютерів.
Всі підходи лише доповнюють один одного.
Принцип 5. Тестові випадки, перевіряються вручну і автоматично. Ефективний процес тестування повинен включати в себе тестові випадки, перевіряються як вручну, так і автоматично.
Перевагою тестів, виконуваних вручну, є їх глибина: вони відображають розуміння розробником наявного кола проблем і структури даних. Перевага автоматичних тестів в їх широті: вони виконують перевірку великого діапазону значень, в тому числі екстремальних, які люди можуть пропустити.
стратегії тестування
Тепер ми переходимо від практики тестування до досліджень нових технологій тестування, які, однак, уразливі в сенсі ризиків розумового процесу. Ви придумали ідею, яка, як вам здається, обіцяє удосконалення і підтверджується вашої інтуїцією. Тестування - це складний процес, і після об'єктивного аналізу далеко не всі розумні ідеї виявляються корисними. Типовий приклад цього - випадкове тестування. Інтуїтивно здається, що будь-яка стратегія, яка використовує знання про програму, повинна бути краще випадкового введення. Однак об'єктивні показники, такі як число знайдених помилок, свідчать про те, що випадкове тестування часто перевершує здавалися розумними ідеї. В огляді Річарда Хемлета, присвяченому випадковому тестування (Encyclopedia of Software Engineering, JJ Marciniak, ed., Wiley, 1994), наводиться захоплююче протиставлення людського знання і наукового аналізу.
Ніщо не замінює емпіричні оцінки.
Принцип 6. Емпіричні оцінки стратегій тестування. Оцінюйте будь-яку стратегію тестування, проте, якою б цікавою вона не здавалася, вдавайтеся до об'єктивної оцінки, використовуючи точні критерії в відтворюваному процесі тестування.
Я радів, як дитина, читаючи в книзі «Життя бджоли» (The Life of the Bee, Fasquelle, 1901) бельгійського драматурга Моріса Метерлінка про те, що відбувається, якщо помістити кілька бджіл і мух в пляшку і перевернути її денцем до джерела світла. Як показано на рис. 1, бджоли, залучені світлом, будуть битися об скло і помруть від голоду і виснаження. Мухи ж, нічого не розуміють, випробують всі напрямки і вилетять з пляшки через пару хвилин. Метерлінк був поетом, а не професійним біологом, і я не знаю, чи проводив він насправді цей експеримент, але це прекрасна метафора для тих випадків, коли, очевидна дурниця перевершує очевидний розум, як це часто відбувається при тестуванні.
критерій оцінки
При застосуванні останнього принципу залишається питання, якою ж критерій використовувати. Література з тестування пропонує такі показники, як «число тестів, вперше викликали збій програми». Для практиків даний показник далеко не найкорисніший. Ми хочемо знайти всі помилки, а не всього лише одну. Припустимо, що використання критерію «перша невдача» буде коректним, і цей критерій застосовується повторно. Але наступні невдачі можуть мати зовсім іншу природу; а автоматичний процес повинен виявляти максимально можливу кількість помилок, а не зупинятися на першій.
Число тестів теж не дуже корисно ні для менеджерів (яким потрібно допомогти прийняти рішення про те, чи можна припиняти тестування і випускати продукт), ні для користувачів (яким потрібно оцінювати щільність помилок). Більш адекватним показником є час тестування, необхідну для виявлення помилок. З іншого боку, ми ризикуємо віддати перевагу стратегіям, які можуть швидко виявляти помилки, але тільки після тривалого процесу продумування тесту, що збільшує загальний час. Ось чому (як і мухи, які вилітають швидше бджіл) дурна, на перший погляд, стратегія, така як випадкове тестування, в цілому може виявитися краще.
Часто використовуються і інші показники, в тому числі різного роду ступінь охоплення тестів (такі як ступінь охоплення команд, гілок або шляхів). Інтуїтивно вони здаються більш корисними, але фактично немає переконливих підтверджень того, що більш високий ступінь охоплення якось впливає на якість. Фактично кілька останніх досліджень показали негативну кореляцію. Якщо модуль має більш високу ступінь охоплення тестів, то, як правило, це відбувається тому, що ви знаєте, що з цим модулем пов'язані певні складності, і, дійсно, часто він буде містити більше помилок.
Більше ніж будь-який з цих показників, має значення те, наскільки швидко стратегія породжує невдачі, що дозволяють виявляти помилки.
Принцип 7. Критерій оцінки. Найважливіше властивість стратегії тестування - це число виявлених помилок як функція часу.
Функція виявлення, тобто число помилок в залежності від часу fc (t), корисна з двох причин - використовуючи програмну базу з відомими помилками, можна оцінити стратегію, подивившись, скільки помилок база дозволить виявити за цей час. Менеджери проектів можуть додати fc (t) в модель надійності для оцінки того, скільки ще помилок залишилося, і відповісти на старе питання «Коли закінчувати тестування?»
***
Ми намагалися не відходити від теми статті: перший принцип говорить про те, що тестування - це породження невдач; останній - про кількісний підтвердження цього загального міркування, що також лежить в основі всіх інших принципів. n
Бертран Мейер ( [email protected] ) - професор програмної інженерії Вищої політехнічної школи (Цюріх, Швейцарія) і головний архітектор компанії Eiffel Software (Санта-Барбара, Каліфорнія).
Bertrand Meyer, Seven Principles of Software Testing. IEEE Computer, August 2008. IEEE Computer Society, 2008. All rights reserved. Reprinted with permission.
* Я дотримуюся стандартної термінології IEEE. Незадовільне виконання програми - це «невдача» (failure), яка вказує на «помилку» (fault) в програмі, яка сама по собі є наслідком «помилки» (mistake) програміста. Неформальним терміном «дефект» (bug) можуть називати будь-яке з цих явищ. - Прим. автора.
Безумовно, зв'язок між тестами і якістю програм існує, але вона досить слабка?Менеджери проектів можуть додати fc (t) в модель надійності для оцінки того, скільки ще помилок залишилося, і відповісти на старе питання «Коли закінчувати тестування?