Створює об’єкти, які, на вашу думку, вам знадобляться в першому тесті в TDD


15

Я досить новачок у TDD, і у мене виникають проблеми при створенні мого першого тесту, коли він постає перед будь-яким кодом реалізації. Без будь-яких рамок до коду реалізації, я можу написати свій перший тест, проте я хочу, але він, як видається, завжди виявляється заплутаним моїм способом мислення Java / OO про проблему.

Наприклад, в моєму Github ConwaysGameOfLifeExample перший тест, який я написав (rule1_zeroNeighbours), я почав зі створення об’єкта GameOfLife, який ще не був реалізований; називається методом набору, який не існував, кроковим методом, який не існував, методом get, який не існував, а потім використаний актар.

Тести розвивалися, коли я писав більше тестів і реконструювався, але спочатку це виглядало приблизно так:

@Test
public void rule1_zeroNeighbours()
{
    GameOfLife gameOfLife = new GameOfLife();
    gameOfLife.set(1, 1, true);
    gameOfLife.step();
    assertEquals(false, gameOfLife.get(1, 1));
}

Це виглядало дивним, коли я змушував розробку проекту базуватися на тому, як я вирішив на цьому ранній стадії написати цей перший тест.

Як ви розумієте, TDD це добре? Здається, я слідую принципам TDD / XP в тому, що мої тести та впровадження розвивалися з часом із рефакторингом, і тому, якби ця початкова конструкція виявилася марною, вона була б відкрита для змін, але відчувається, що я змушую направити на рішення, починаючи таким чином.

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


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

Відповіді:


9

Це виглядало дивним, коли я змушував розробку проекту базуватися на тому, як я вирішив на цьому ранній стадії написати цей перший тест.

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

Я думаю, що з них ви віддаєте перевагу (або де ви потрапляєте в середину) - це те, що вам потрібно розкрити для себе як перевагу. Корисно зрозуміти плюси і мінуси кожного підходу. Напевно, їх багато, але я б сказав, що головні з них:

Професійний дизайн

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

Pro Тест-водіння дизайн

  • Створюючи свою реалізацію навколо клієнта свого коду (ваших тестів), ви отримуєте прихильність YAGNI майже безкоштовно, доки не почнете писати зайві тестові приклади. Більш загально, ви отримуєте API, який розроблений навколо його використання споживачем, і це, в кінцевому рахунку, те, що ви хочете.

  • Ідея скласти купу діаграм UML перед написанням будь-якого коду, а потім просто заповнити прогалини є приємною, але рідко реалістичною. У «Кодексі» Стіва МакКоннелла дизайн добре відомий як «зла проблема» - проблема, яку ви не можете повністю зрозуміти, спочатку хоча б частково не вирішивши її. Поєднайте це з тим, що основна проблема може змінитися через зміни вимог, і ця модель дизайну починає відчувати себе трохи безнадійно. Тест-водіння дозволяє вам просто відкусити одну частину роботи за один раз - в дизайні, а не просто в реалізації - і знати, що принаймні протягом життя червоний в зелений, це завдання все ще буде актуальним і актуальним.

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


Посилання дуже добре прочитав Бен. Дякуємо, що поділилися цим.
RubberDuck

1
@RubberDuck Ласкаво просимо! Насправді я не повністю з цим погоджуюся, але я думаю, що це чудова робота, аргументуючи цю точку зору.
Бен Аронсон

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

17

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

З практичного одиничного тестування з JUnit та Mockito :

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

Ваш тест не робить великої спроби розробити API. Ви створили надзвичайну систему, де вся функціональність міститься у зовнішньому GameOfLifeкласі.

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

Легко промальовувати крок "написати тест, який не вдається". Але написання невдалого тесту, який працює так, як ви цього хочете, є ядром TDD.


1
Вважаючи, що Cell є просто обгорткою для boolean, такий дизайн, безумовно, буде гіршим за продуктивність. Хіба що в майбутньому це не потрібно буде розширити на інші стільникові автомати з більш ніж двома станами?
користувач253751

2
@immibis Це химерно ставиться до деталей. Можна почати з класу, який представляє колекцію комірок. Ви також можете мігрувати / об'єднувати клас комірок та його тести з класом, що представляє колекцію комірок пізніше, якщо продуктивність не викликає проблем.
Ерік

@immibis Кількість живих сусідів може бути збережена з міркувань продуктивності. Кількість кліщів клітина жива з кольорових причин ..
Blorgbeard вийшов

@immibis передчасна оптимізація - це зло ... Більше того, уникнення примітивної одержимості - це чудовий спосіб написання коду хорошої якості, незалежно від того, скільки держав він підтримує. Подивіться на: jamesshore.com/Blog/PrimitiveObsession.html
Павло

0

З цього приводу різні школи думок.

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

Деякі кажуть: добре написати тест спочатку перевірити, чи він смокче (чи ні) мураха, а потім створити відсутні класи / методи

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

Ви самі вирішите, яким способом працювати. ІМХО обидва підходи справедливі.


0

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

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

Що може допомогти вам - використовувати огірок або подібне для написання своїх тестів.


0

Перш ніж почати писати тести, слід подумати про те, як створити систему. Ви повинні витратити значну кількість часу під час фази проектування. Якщо ви зробили це, ви не заплутаєтеся в замішанні на TDD.

TDD - це лише посилання на підхід до розробки : TDD
1. Додайте тест
2. Запустіть усі тести і подивіться, чи не вийшов новий.
3. Напишіть якийсь код
4. Запустіть тести
5. Код Refactor
6. Повторіть

TDD допомагає покрити всі необхідні функції, які ви запланували, перш ніж розпочати розробку свого програмного забезпечення. посилання: Переваги


0

Мені не подобаються тести системного рівня, написані на Java або C # з цієї причини. Подивіться на SpecFlow для c # або одного з тестових рамок на основі огірків для Java (можливо, JBehave). Тоді ваші тести можуть виглядати приблизно так.

введіть тут опис зображення

І ви можете змінити дизайн об'єкта, не змінюючи всіх системних тестів.

("Нормальні" одиничні тести чудові при тестуванні одиночних класів.)

Чим відрізняються рамки BDD для Java?

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