Тестування: детерміновані чи недетерміновані?


16

Краще мати або

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

?

Приклад: Ви пишете тестовий набір для тестування функціональності контролера у програмі MVC. Контролер вимагає даних програми з бази даних як вхідних даних під час тесту. Для цього є два варіанти:

  • Ви вказуєте, який рядок (и) з тестової бази даних обраний як вхідний (наприклад, 10-й та 412-й рядки)
  • Ви використовуєте генератор випадкових чисел для псевдовипадкового вибору даних із бази даних (два ряди, вибрані генератором випадкових чисел)

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

Які причини обрати одне над іншим?


5
Іноді цей тест просто не вдається. martinfowler.com/articles/nonDeterminism.html

Дякуємо за це посилання Маючи на увазі цю статтю, я відчув, що потрібно уточнити, що недетермінізм означає в контексті цього тестового набору. Оскільки дані вибираються випадковим чином із бази даних, всі дані, що надходять до контролера, є типовими даними за замовчуванням. Це означає, що помилкові негативи не існують у тестовому наборі, якщо мова йде про недетермінізм. Певним чином ця випадковість імітує користувача, вибираючи дані "навмання" для використання в контролері. Це не обов’язково той самий недетермінізм, про який йдеться у статті, правда?
DCKing


10
@DCKing: Подумайте, що станеться, якщо ваш тест не вдасться. Гаразд, у вас помилка. Ага, тепер що? Запустити його знову в режимі налагодження! Де це вдається! Як це відбувається наступні сто разів, коли ви запускаєте його, а потім списуєте питання як удар космічного проміння. Недетермінісцим у тестах звучить абсолютно нездійсненно. Якщо ви відчуваєте необхідність прикривати більше землі у своїх тестових випадках, прикрийте більше ґрунту. Запустіть свій RNG з набором насіння і кілька разів проведіть "тест" з послідовно випадковими значеннями.
Фоші

1
(нарешті дістався до машини, де я міг правильно шукати твіттер - " Цей тест часом просто не вдається " - це від #FiveWordTechHorrors в Twitter - хотів належним чином зарахувати його)

Відповіді:


30

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

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

РЕДАКТУВАННЯ: Використання генератора випадкових чисел для вибору деяких тестових даних - це ІМХО іноді ознака занадто ледачого збору добрих даних тесту. Замість того, щоб кидати 100 000 випадково вибраних тестових значень і сподіватися, що цього буде достатньо, щоб випадково виявити всі серйозні помилки, краще скористайтеся своїм мозком, виберіть від 10 до 20 «цікавих» випадків і використовуйте їх для тестового набору. Це призведе не тільки до кращої якості ваших тестів, але і до значно вищої продуктивності набору.


Дякую за вашу відповідь. Яка ваша думка щодо коментаря, який я зробив до свого запитання?
DCKing

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

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

1
У деяких контекстах інтерфейсу (наприклад, ігри, що приймають введення контролера), які мають тестові програми, що генерують випадкові введення ключів, можуть бути корисними для стрес-тестування. Вони можуть виявити дефекти, які важко знайти при навмисному введенні.
Gort the Robot

@StevenBurnap: ну, як я розумію питання, я думаю, що ОП мав на увазі більш звичайні тести регресії. Звичайно, я погоджуюся, тест на стрес - це особливий випадок, який також може залежати від обладнання та призводити до недетермінованої поведінки, навіть коли ви не використовуєте генератор випадкових випадків. Це те, що описано в статті, з якою Майкл посилається в першому коментарі під питанням. І навіть у стрес-тесті з випадковим введенням можна хоча б спробувати зробити поведінку більш детермінованою, використовуючи визначений випадковий насіння.
Док Браун

4

І детерміновані, і недетерміновані мають місце

Я поділив би їх так:

Одиничні тести.

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

Функціональні та вхідні стрес-тести.

Вони можуть використовувати недетермінований підхід із наступними застереженнями:

  • цей факт чітко окреслений і заперечений
  • вибрані випадкові значення записуються в журнал і їх можна повторно спробувати вручну

3

І те й інше.

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

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

  • Порожній список
  • Список лише з одним елементом
  • Список із тим самим елементом
  • Список з декількома унікальними елементами
  • Список з декількома елементами, деякі з яких є дублікатами
  • Список з NaN, INT_MINіINT_MAX
  • Список, який уже частково відсортований
  • Список з 1000000000 елементів

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

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

  • Використовуйте недетерміновані тести, щоб знайти помилки у своєму коді.
  • Використовуйте детерміновані тести для перевірки виправлень у своєму коді.

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


-1

Ви насправді не хочете детермінованих проти недетермінованих.

Те, що ви можете хотіти, це "завжди одне і те ж" проти "не завжди те саме".

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

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


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