Як дитині ваші дитячі кроки в TDD?


37

Сьогодні ми тренували TDD і виявили наступний момент непорозуміння.

Завдання полягає у введенні «1,2» повернення суми чисел, що дорівнює 3. Що я написав (на C #):

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]); //task said we have two numbers and input is correct

Але інші хлопці вважали за краще це робити інакше. По-перше, для введення "1,2" вони додали наступний код:

if (input == "1,2")
   return 3;

Потім вони запровадили ще один тест на введення "4,5" та змінили реалізацію:

if (input == "1,2")
   return 3;
else if (input == "4,5")
   return 9;

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

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

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


25
Настільки крихітні, що мої колеги гулять "Ооахх дазсо куууууте"
Адель

6
@Adel: Майже задихнувся від мого сніданку, клавіатура зараз повна або колючка та крихти
Binary Worrier

2
@Adel, що стосується того, хто не є носієм мови, мені досить складно зрозуміти цей гумор, але, мабуть, вашим колегам подобається питання :)
SiberianGuy

8
@Idsa: Він переносить відповідь колег, коли показують дитині перші кроки "Ооааааааааа" = "О, це так мило" (вимовляється співаючою піснею-не-що-дуже-мило), з їхньою відповіддю коли бачите Unit Tests, написану Адель, дивлячись на дитячі кроки, вони говорять "О, це так мило". Реакція на - дійсні кроки для немовлят = реакція на одиничні тести "дитячі кроки".
Бінарний занепокоєння

3
@Binaryworrier бажаю, щоб я міг дати вам реальні моменти, щоб витратити час на пояснення батьків
Ендрю Т Фіннелл

Відповіді:


31

Напишіть найпростіший код, завдяки якому тести проходять.

Ніхто з вас цього не зробив, наскільки я бачу.

Baby Step 1.

Тест: Для введення "1,2" повернути суму чисел, яка дорівнює 3

Зробіть тест невдалим:

throw NotImplementedException();

Зробіть тестовий пропуск:

return 3;

Baby Step 2.

Тест: Для введення "1,2" повернути суму чисел, що дорівнює 3

Тест: Для введення "4,5" повернути суму чисел, що дорівнює 9

Другий тест не вдається, тому пройдіть його:

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]);

(Шлях простіше, ніж список, якщо ... повернути)

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

Аргумент полягає в тому, що якщо ви не напишете другий тест, то пізніше може з’явитися якась яскрава іскра, яка «переробляє» ваш код, щоб прочитати:

return input.Length; # Still satisfies the first test

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


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

@Idsa - Так, і, чим більше тестів ви напишете, тим більше шаленою має бути реалізація. input.Lengthце не так далеко, особливо якщо вхід до методу є вимірюванням якогось файлу десь і ви необачно назвали свій метод Size().
pdr

6
+1. Що стосується того, як вивчити TDD, це правильний шлях. Після того, як ви дізнаєтесь про це, іноді ви можете перейти безпосередньо до очевидного впровадження, але щоб відчути TDD, це набагато краще.
Карл Манастер

1
У мене питання стосовно самого "тесту". Ви б написали новий тест для введення "4,5" чи змінили оригінальний тест?
mxmissle

1
@mxmissle: Я б написав новий тест. Це не займе багато часу, і ви закінчите вдвічі більше тестів, щоб захистити вас, коли пізніше ви зробите рефакторинг.
пдр

50

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

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


+1 і спасибі за те, що змусив мене шукати і вивчати нове слово (асинін)
Мар'ян Венема

12
+1 за те, що називав це нерозумно дурним. TDD - це все приємно і таке, але, як і будь-яка сучасна техніка розкрученого програмування, ви повинні подбати про те, щоб не загубитися.
вівторок

2
"Особливо, якщо оригінальна проблема, яку ви вирішуєте, вже дуже мала". - Якби введення було два входи, які потрібно додати разом, я би погодився з цим, але я не переконаний, коли це "розділити рядок, проаналізувати два ints з результату та додати їх". Більшість методів у реальному світі не набагато складніші за це. Насправді має бути ще тестів, щоб охопити крайні випадки, такі як знаходження двох коми, нецілих значень тощо
pdr

4
@pdr: Я згоден з вами, що для обробки кращих справ має бути більше тестів. Коли ви пишете їх і помічаєте, що ваша реалізація повинна змінитись, щоб обробити їх, усіляко зробіть це. Напевно, у мене просто виникає проблема з тим, як зробити кроки зиготи до першого щасливого шляху, "очевидного впровадження", замість того, щоб просто записати це і піти звідти. Я не бачу значення в написанні заяви if, про яке знає кожна клітковина в моєму тілі, просто зникне наступного моменту.
Крістоф Ванфлетерен

1
@ChristopheVanfleteren: Коли Бек описує очевидну реалізацію, він використовує суму двох точок як приклад і все-таки кидає величезне драматичне попередження про те, як ти помреш від сорому, якщо твоя пара / рецензент може придумати простіший код, який робить пропускний тест. Це абсолютна впевненість, якщо ви пишете лише один тест для цього сценарію. Крім того, я можу придумати щонайменше три "очевидні" способи вирішення цієї проблеми: розділити та додати, замінити кому на + та оцінити, або використовувати регулярний вираз. Сенс TDD полягає в тому, щоб привести вас до правильного вибору.
pdr

19

Кент Бек висвітлює це у своїй книзі «Розробка тестів: за прикладом».

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

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

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

З книги:

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


18

Я бачу це як слід за буквою закону, але не його духом.

Кроки вашої дитини повинні бути:

Як можна простіше, але не простіше.

Також дієслово у способі є sum

if (input == "1,2")
   return 3;

це не сума, це тест на конкретні входи.


4

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

OTOH це стосується лише дійсно тривіальних кроків, як у наведеному вище прикладі. Щодо більш складного, якого я не можу повністю затримати в своєму розумі і / або де я не на 110% впевнений у результаті, я вважаю за краще робити крок за часом.


1

Під час першого виходу на дорогу TDD розмір кроків може бути заплутаною проблемою, як це ілюструє це питання. Питання, які я часто задавав собі, коли я вперше почав писати тестові програми; Чи допомагає тест, який я пишу, сприяти розвитку моїх додатків? Це може здатися банальним і не пов’язаним з деякими, але затримайтеся на хвилині зі мною.

Тепер, коли я збираюся писати будь-яку заявку, я зазвичай починаю з тесту. Скільки кроків цього тесту багато в чому стосується мого розуміння того, що це я намагаюся зробити. Якщо я думаю, що в мене в голові дуже сильно спостерігається поведінка класу, тоді крок буде великим. Якщо проблема, яку я намагаюся вирішити, є набагато менш зрозумілою, тоді крок може бути просто тим, що я знаю, що йде метод, названий X, і що він поверне Y. На даний момент у методу навіть не буде параметрів є ймовірність, що назва методу та тип повернення зміниться. В обох випадках тести рухають мою розробку. Вони розповідають мені речі про мою заяву:

Чи справді цей клас, який у мене в голові, буде працювати?

або

Як чорт я навіть збираюся це зробити?

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

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

Я сподіваюся, що вам сподобалось, коли ви тренували палицю з TDD. ІМХО, якби більше людей були піддані тестуванню, то світ був би кращим місцем :)


1

У букварі про тестування одиниць я читав той самий підхід (кроки, які виглядають дійсно, справді крихітні), і як відповідь на запитання "наскільки крихітними вони повинні бути", щось мені сподобалось, що було (перефразоване) так:

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

Тож, можливо, ваш колега просто трохи сором’язливий :)


1

Чи не вся справа в тому, що реалізація методу не має значення, доки тести будуть успішними? Подовження тестів у другому прикладі швидше завершиться, але в обох випадках може призвести до відмови.


1
Неважливо, якщо вам зовсім не байдуже витрачати свій час
SiberianGuy

1

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

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


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