Тестування списку ... Все в одному тесті або один тест для кожної умови?


21

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

f(null) -> null
f(empty) -> empty
f(list with one element) -> list with one element
f(list with 2+ elements) -> list with the same number of elements, doing what expected

Для цього, який найкращий підхід?

  • Тестування всіх випадків у тому самому (методі) тесті під назвою "WorksAsExpected"
  • Розміщення по одному тесту для кожного випадку, таким чином
    • "WorksAsExpectedWhenNull"
    • "WorksAsExpectedWhenEmpty"
    • "WorksAsExpectedWhenSingleElement"
    • "WorksAsExpectedWhenMoreElements"
  • Ще один вибір, про який я не думав :-)


2
Я б написав це як окремі тестові випадки. Ви можете використовувати параметризовані тести, якщо ваша тестова система підтримує це.
jonrsharpe

5
Якщо ви пишете свої тести в заданому ... Коли ... Тоді стилі, то стає зрозумілим, що вони справді повинні бути перевірені окремо ...
Роббі Ді

1
Я просто хотів би додати: ІМО, добре розділити крайові випадки (наприклад, нульові та порожні) на окремі тести, тому що вони часто включають спеціальну логіку випадку для різних можливих реалізацій, і якщо ці тести не вдаються, вони чітко вказуватимуть у яким чином не виходить код тесту (вам не доведеться копати глибше або налагоджувати тестовий випадок, щоб з’ясувати, що відбувається).
Філіп Мілованович

1
Список з повторюваними елементами?
atayenel

Відповіді:


30

Просте правило, яке я використовую для того, чи потрібно проводити набір тестів в одному тестовому випадку, чи багато, таке: чи передбачає це лише одна установка?

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

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

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


14

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

Можливі інструменти, засновані на ваших рамках:

  • Теорії . Теорія дозволяє перевірити низку фактів про сукупність даних. Потім рамка буде подавати ваші тести кількома сценаріями тестових даних - або польовим, або статичним методом, який генерує дані. Якщо деякі ваші факти застосовуються з урахуванням якихось передумов, а інші - ці рамки не вводять концепцію припущення . Ви Assume.that()просто пропускаєте тест даних, якщо вони не відповідають умові. Це дозволяє вам визначити "Працює так, як очікувалося", а потім просто подати їй багато даних. Переглядаючи результати, у вас є запис для батьківських тестів, а потім підзапис для кожної частини даних.
  • Параметризовані тести . Параметризовані тести були попередником теорій, тому може не бути такої передумови перевірки, яку ви можете мати з теоріями. Кінцевий результат той самий. Ви переглядаєте результати, у вас є батьківський запис для самого тесту, а потім конкретний запис для кожної точки даних.
  • Один тест з декількома твердженнями . На те, щоб здійснити налаштування, потрібно менше часу, але ви в кінцевому підсумку виявляєте проблеми трохи за один раз. Якщо тест буде занадто довгим і занадто багато різних перевірених сценаріїв, є два великих ризики: запустити потрібно буде багато часу, і ваша команда набридне ним і вимкне тест.
  • Кілька тестів з подібною реалізацією . Важливо зазначити, що якщо твердження різні, вони тести не перетинаються. Однак це була б загальноприйнята мудрість команди, орієнтованої на TDD.

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

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


5

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

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

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

Досить інший підхід - тестування власності . Ви б створили різні (параметризовані) тести, які стверджують різні властивості вашої функції, не вказуючи конкретні вхідні дані. Наприклад, властивість може бути: для всіх списків xsсписок ys = f(xs)має ту саму довжину, що і xs. Потім тестова рамка генеруватиме цікаві списки та випадкові списки та стверджуватиме, що ваші властивості містять усі вони. Це відхиляється від введення вручну прикладів, оскільки вибираючи приклади вручну, можна пропустити цікаві крайові випадки.


Чи не повинно "пропустити" в останньому реченні "знайти"?
Роббі Ді

@RobbieDee Англійська мова неоднозначна, виправлена.
амон

3

Проведення одного тесту для кожного випадку є доцільним, оскільки тестування єдиної концепції у кожному тесті - це хороша інструкція, яка часто рекомендується

Дивіться цю публікацію: чи добре мати кілька тверджень в одному тесті одиниці? . Там також є відповідна і детальна дискусія:

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

[...]

Тести повинні провалюватися лише з однієї причини, але це не завжди означає, що має бути лише одна заява Assert. ІМХО важливіше дотримуватися схеми "Упорядкувати, діяти, підтверджувати".

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


0

На мій погляд, це залежить від стану тесту.

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

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