Чи не тестування одиничних тверджень не порушує принцип DRY?


12

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

Тож чи односхильне тестування порушує DRY?

І чи є хороше правило, яке слід дотримуватися, щоб знайти хороший баланс, як, наприклад, мати один тест на метод ? *

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


5
Ви можете витягти код, який ви копіюєте, методами
Ісмаїл Бадаві

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

1
Ви створюєте щось у заданому стані для тестування? Це звучить як кріплення.
Дейв Хіллєр

@DaveHillier так, сьогодні я навчився нового слова. Дякую :)
Korey Hinton

залежить від того, як ви інтерпретуєте 1 аргумент за тест, якщо ви маєте на увазі один виклик Assert *, то так, якщо ви також хочете переконатись, що інваріанти все ще тримаються (потім знову витягніть це в метод) або якщо є кілька ефектів, які ви просто можете ' t випробування в одному Assert (або якщо ви це зробили, тоді не було б зрозуміло, чому це не вдалося)
храповий вирод

Відповіді:


14

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

public void AddNewCustomer_CustomerExists_ThrowsException()

Ось чому у вас є одне твердження за тест, щоб кожен метод (і його назва) відповідав умові, яку ви стверджуєте.

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

У TDD жоден тест не є YAGNI, оскільки ви пишете тести, засновані лише на тому, що вам потрібно зробити ваш код. Якщо він вам не потрібен, ви не пишете тест.


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

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

5

Тож чи односхильне тестування порушує DRY?

Ні, але це сприяє порушенню.

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

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

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

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

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


1
Для тестів важливіше бути DAMP, ніж DRY (Описові та значущі фрази).
Йорг W Міттаг

2

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

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

Використовуйте такі методи, як зазвичай, для структуризації коду. Під час тестів на рефакторинг звичайний TDD Red-Green-Refactor не застосовується, замість цього застосовується "Refactoring in the Red". Це,

  1. навмисно розбийте свій тест,
  2. зробіть рефакторинг
  3. виправити тест

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

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

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