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


14

Скажімо, я реалізую щось просте, наприклад пошук відсортованого списку / масиву. Функція (в c #) буде схожа на:

static int FindIndex(int[] sortedList, int i);

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

Отже, моє запитання: чи слід намагатися написати тести, які гарантують продуктивність з точки зору складності алгоритму, і якщо так, то як?

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

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

Хтось ще вважав це (напевно)? Спасибі.


@ steenhulthin - Я дозволю цьому закипіти тут і перевірити це. Я ніколи не був там.
СерПентор

btw, приємне запитання. +1
Рафаель Колуччі

Відповіді:


13

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

Абсолютні показники роботи можуть бути перевірені механічно і можуть зробити корисні тестові одиниці. Якщо продуктивність має значення, то ви можете вказати поріг: "Цей запит повинен тривати не більше 50 мс для запуску на 10 6 чисел і не більше 60 мс на 10 7 чисел." Для цього можна створити одиничний тест.

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


Це також мій інстинкт. Але те, що мене змусило задуматися, це коли гарантії продуктивності на рамках. Приклад: якщо я пам'ятаю правильно, у stl є деякі гарантії алгоритмічної складності (тут можна вимкнути).
СерПентор

Тільки тому, що бібліотека надає деякі гарантії, не означає, що вони повинні бути перевірені одиницями.
svick

@Tobias Brick: Тестування чогось і визначення чогось - це дві різні речі.
DeadMG

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

3

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

Сподіваюся, це допомагає!


0

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

З мого досвіду настройки продуктивності, як і в цьому прикладі , що відбувається, якщо якийсь алгоритм (наприклад) O (n ^ 2), це може бути добре, доки відсоток часу, який він займає, ніколи не потрапляє на радари.

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

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


0

Я не думаю, що те, що ти хочеш робити, - це тестування одиниць.

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

З Вікіпедії : Не можна очікувати, що тестування виявить кожну помилку в програмі: неможливо оцінити кожен шлях виконання у всіх, крім самих тривіальних програм. Те саме стосується тестування одиниць. Крім того, тестування блоку за визначенням перевіряє лише функціональність самих підрозділів. Тому він не буде вловлювати помилки інтеграції або більш широкі помилки на системному рівні (наприклад, функції, що виконуються в декількох одиницях, або нефункціональні тестові області, такі як продуктивність). Тестування одиниць повинно проводитися разом з іншими тестуваннями програмного забезпечення. Як і всі форми тестування програмного забезпечення, одиничні тести можуть показувати лише наявність помилок; вони не можуть показати відсутність помилок.

Існують інші види інструментів та моделей для вимірювання продуктивності. Одне з яких я зараз пам'ятаю - це тестування на прийняття, орієнтоване на нефункціональні вимоги.

Існує небагато інших, таких як тестування працездатності (яке використовує стрес-тестування, тестування навантаження тощо).

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

Отже, коротка відповідь - ні, ви не повинні турбуватися про це під час тестування коду.


0

Передача в компаратор і відстеження кількості викликів буде працювати для простих цілей, таких як перевірка того, що кількість порівнянь під час пошуку за фіксованим входом (скажімо new int[] { 1,2,3, ... , 1024 }) залишається нижче 10. Це, принаймні, уточнити свої наміри щодо того, як повинен поводитися алгоритм.

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

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