Чи можна застосовувати методологію TDD зверху вниз?


13

Мені незрозуміло, як TDD, методологія, розглядає такий випадок. Припустимо, я хочу реалізувати алгоритм злиття в Python. Починаю писати

assert mergesort([]) === []

і тест не вдається

NameError: назва 'mergesort' не визначено

Потім додаю

def mergesort(a):
    return []

і мій тест проходить. Далі додаю

assert mergesort[5] == 5

і мій тест не вдається

AssertionError

з яким я проходжу

def mergesort(a):
    if not a:
        return []
    else:
        return a

Далі додаю

assert mergesort([10, 30, 20]) == [10, 20, 30]

і мені зараз потрібно спробувати зробити цей прохід. Я "знаю" алгоритм злиття, тому пишу:

def mergesort(a):
    if not a:
        return []
    else:
        left, right = a[:len(a)//2], a[len(a)//2:]
        return merge(mergesort(left)), mergesort(right))

І це не вдається

NameError: ім'я "злиття" не визначено

Тепер ось питання. Як я можу закінчитись та почати впроваджувати mergeвикористання TDD? Здається, я не можу, тому що у мене це "висяче" невиконане, невдале тест mergesort, яке не пройде, поки не mergeбуде закінчено! Якщо цей тест зависає, я ніколи не можу робити TDD, тому що я не буду "зеленим" під час створення своїх ітерацій TDD merge.

Схоже, я застряг у наступних трьох потворних сценаріях, і хотів би знати (1), якому з них надає перевагу спільнота TDD, або (2) чи є інший підхід, який я мені не вистачає? Я спостерігав кілька покрокових інструкцій дядька Боба TDD і не згадую, як раніше бачив такий випадок!

Ось 3 випадки:

  1. Реалізуйте об'єднання в інший каталог з іншим тестовим набором.
  2. Не турбуйтеся про те, що ви розробляєте функцію помічника зеленого кольору, просто вручну слідкуйте, які тести ви дійсно хочете пройти.
  3. Коментуйте (GASP!) Або видаляйте рядки в mergesortцьому дзвінку merge; після того, як приступити mergeдо роботи, покладіть їх назад.

Усі вони виглядають на мене дурними (чи я дивлюсь на це неправильно?). Хтось знає кращий підхід?


2
Частина мети TDD - допомогти вам створити дизайн програмного забезпечення. Частиною цього процесу проектування є виявлення того, що потрібно для досягнення бажаного результату. У випадку mergesort, оскільки це вже дуже чітко визначений алгоритм, цей процес виявлення не потрібен, і він потім стає питанням відображення того, що ви вже знаєте, як дизайн на серію одиничних тестів. Імовірно, ваш тест верхнього рівня стверджує, що ваш тестований метод приймає несортовану колекцію та повертає відсортовану ...
Роберт Харві

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

4
Дизайн не виростає сам з одиничних тестів; якщо ви очікуєте, що mergesortдизайн природним чином вийде з червоно-зеленого рефактора, це не відбудеться, якщо ви не керуєте процесом на основі наявних знань mergesort.
Роберт Харві


1
У TDD mergeпотрібно вигадувати лише на етапі "рефакторингу". Якщо ви бачите, що mergeметод може бути запроваджений для проходження тестування, mergesortви спершу зробите тести без mergeметоду. Потім рефакторинг вашої реалізації, ввівши mergeметод.
Фабіо

Відповіді:


13

Ось кілька альтернативних способів розглянути ваші варіанти. Але спочатку правила TDD від дядька Боба з наголосом на мене:

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

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

Або, по черзі, ви починаєте з написання операції злиття inline, а потім переробляєте її у функцію після отримання тесту на роботу.

Інша інтерпретація полягає в тому, що ви пишете злиття, ви знаєте, що вам знадобиться mergeоперація (тобто це не YAGNI, а це "достатнє" правило намагається скоротити). Тому ви повинні почати з тестів на злиття і лише потім переходити до тестів на загальний сорт.


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

@RayToal - я фактично схиляюся до підходу до повного тестування mergeоперації перед тим, як робити сортування (а також до окремого тестування partitionоперації). Я вважаю, що заявляється про переваги виникаючого дизайну випливає з повільного прагнення до відомих цілей. У випадку злиття, я не думаю, що ціль - це сортування в цілому (адже тоді ви закінчите сортування бульбашок). Ви знаєте основні операції, тому працюєте над цими операціями; сорт здебільшого задумливий.
kdgregory

1
Є четвертий варіант. Передайте mergeфункцію mergesortта висміюйте її поведінку. Потім поверніться назад і mergeспочатку застосуйте тест. Делегати є дивним ™.
RubberDuck

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