TDD

индекс
107,68

Опыт применения TDD у нас в команде

Мы у себя применяем. Pairing и прочие атрибуты. :) Могу сказать точно — удовлетворение от работы гораздо больше, потому что ты запускаешь программу и она работает. Не нужно сидеть в дебаггере и что-то там выяснять. Тесты позволяют свести необходимость в отладке к минимуму. А когда программа падает в дебаггер — это большой стресс. TDD от этого стресса максимально избавляет.

Если кто-то начинает гадать, а сработает ли такой подход или нет — обычно говорим друг-другу: «Напиши тест. :)» И это не рутина, а забава. Игра. Когда тебе не нужно философствовать, а можно взять и попробовать. Самый надежный способ. Потом на основе нескольких «пристрелочных» тестов уже можно принимать архитектурные решения.

И опять же, нас до сих пор охватывает легкий шок и удовольствие, когда мы наконец наколбасив сотню тестов, запускаем приложение — и новая фича работает без сучка без задоринки. Гораздо приятнее, нежели запустить и получить исключение в лоб при непонятных обстоятельствах, не правда ли?

Пример


Мы написали часть приложения, а потом решили перевести на Unity. При этом при существовавшей у нас до этого самописной системе кэширования и «доставания» сервисов, можно было сделать быстро и неправильно, а можно было правильно, но без тестов было бы стремно. Я пошел вторым путем. Не потому что у нас был 90%+ code coverage, а потому что я не терплю «соплей» в коде. В результате под конец рабочего дня удостоверившись, что все тесты выполняются, я на глазах у коллеги написав кофиг Unity, запускаю… и мы вместе снова балдеем. :) Мы просто не верим, что после того, как я перелопатил все классы попутно упрощая дизайн, оно по-прежнему работает!!!

Среда


Причем читать книги — это конечно интересно, но реальность вносит свои коррективы. Например, я открутил со всех кресел подлокотники. Мешают при парном программировании (на фотках из статей везде кресла с подлокотниками). Один монитор удобно повернуть по-вертикали (с кодом), второй — по горизонтали (вообще нигде такого не видел). Но это нам. :) Основная фишка TDD в том, что она избавляет от страха что-то поломать, поэтому если чувствуешь, что нужно сделать рефакторинг, то ты его делаешь, а не вспоминаешь анекдот про сына и отца-программиста… «система работает? работает. вот ты ее и не трогай.» Я могу «трогать» столько, сколько я посчитаю нужным. Граница — лишь здравый смысл. И никакие тесты не «гири». Это свобода!

P.S. Все диаграммы и схемы у нас принципиально от руки.
+43
4 декабря 2008, 03:09
13

комментарии (111)

+2
Denis_in_ua #
Как приятно такие посты читать.
А у нас пока не всегда получается через ТДД работать. Иногда начинается нереальная спешка и тут уже жертвуем тестами в ущерб качеству, лишь бы клиенту показать что-то сегодня.
Потом дописываем тесты. Но будем стремиться к совершенству.
+2
VasilioRuzanni #
Интересно, как это так «не всегда получается». Это значит, что вообще не получается! :)
TDD — это не способ тестирования, это способ разработки, поэтому потом дописывать тесты — вот уже где трата времени.
Ставьте более реалистичные сроки, и главное, что надо понять — тесты — это не то, чем можно пожертвовать. Ибо код потом все равно придется переписывать.
+1
korchasa #
К чему фанатизм? TDD это, конечно, способ разработки, но это не значит, что ему нужно придерживаться всегда.

Если вы делаете oneline'ер на один запуск — вы его тоже тестировать будете? Не весь код надо писать так, чтобы его легко было поддерживать. Это неправильно с точки зрения прибыли вашей фирмы.

Тестами можно пожертвовать, когда это нужно. Стопроцентное покрытие системы тестами — лишняя работа.

TDD infected с 2006 года.
+1
VasilioRuzanni #
Никакого фанатизма как раз таки.
Я и ни разу не упомянул о том, что надо применять TDD всегда и везде. Есть масса исключений. Более того, я упоминал в комментариях ниже, что стопроцентного покрытия на практике почти не бывает (по опыту работы своей команды знаю) — причем, что интересно, не по техническим причинам, а как раз, как вы и говорите — просто не было необходимости или вообще смысла.
Видимо вам удалось использовать TDD на практике, раз уж вы не отрицаете его существования.
Логично, что это не всегда нужно, но, согласитесь, бывают ситуации, когда «нужно», верно?

Пример с 1-лайнером можно было не приводить — не нужно доводить тему до абсурда. Ибо тогда уж можно думать, а вообще стоит ли писать эту самую программу-строчку и вполне может оказаться, что нет. Мы же обсуждаем применение TDD в разработке, а не в написании отдельной строчки кода.
0
korchasa #
>>А у нас пока не всегда получается через ТДД работать.
>Интересно, как это так «не всегда получается». Это значит, что вообще не получается! :)

>>Потом дописываем тесты.
>TDD — это не способ тестирования, это способ разработки, поэтому потом дописывать тесты — вот уже где трата времени.
0
VasilioRuzanni #
Ну вы же поняли контекст. «не всегда получается» — звучит так, как будто «надо бы, но не получается в силу тех или иных причин», а не потому что «не получается потому что и не надо».

TDD, когда он уместен (у нас в практике — почти всегда), является способом разработки, а не тестирования и не вижу тут никаких разногласий с чем-либо.

Поэтому, не понимаю, к чему здесь эти цитаты :)
0
korchasa #
Насчет «звучит» ничего не могу сказать, ибо для меня это звучало по-другому :)

А насчет дописывания тестов — дописывание тестов это, по сути, фиксация требований. ИМХО, лучше это сделать поздно, чем никогда.
0
VasilioRuzanni #
Скажем так, мы и так постоянно дописываем код, под новые требования. Однако мы сначала дописываем именно тесты под новый код, даже если это расширение уже существующего метода класса. А уже потом пишем новый код (который может затронуть старый код, о чем нам сразу скажут тесты).
Тут нет рано или поздно, есть просто определенные правила, вот и все, и мы на практике убедились в том, что нельзя сделать что-то сразу и целиком — всегда приходится дописывать и переписывать, а вот тут тесты серьезно помогают.
Как то так :)
0
zerkms #
а вот тут я не соглашусь. код не должен появляться, пока на него не написан тест.
да и coverage при этом будет далеко не 100%.
+2
eisernWolf #
Своим клиентам я гарантирую 90% покрытие кода для нагруженных логикой компонентов. И это чистейшая правда. Реальные цифры «в моменте» — 85% — 100%. Т.е. для DDD модели у нас 95% — 98% процентов покрытие кода, т.к. вследствие архитектуры легко поддается тестированию как с привязкой к БД, так и без. Для какого-нибудь класса разряда Bootstrapper тесты не пишутся. Существует полно исключений, где тесты будут просто избыточны. В среднем по проекту у нас code coverage колеблется на уровне 70% — 75% из-за того, что некоторые моменты тестировать не нужно, некоторые — просто невозможно. А где-то тулза ошибается. :) Это не тесты ради тестов. Любой тест у нас проверяет состояние или необходимое поведение. Если что-то начинает валится, то сразу понимаешь, какой кейс не выполняется и собственно говоря какую строчку кода править при этом.
0
zerkms #
вы правильно понимаете, что «100% покрытие кода тестами» это:
1. метод должен быть покрыт тестом
2. должны быть учтены все прецеденты
?

просто цифры в 95-98% выглядят фантастически…
0
eisernWolf #
Вот тебе скріншот с жівого проекта:
Free Image Hosting at www.ImageShack.us

QuickPost Quickpost this image to Myspace, Digg, Facebook, and others!
0
zerkms #
собственно о чём я и говорил — как можно программно (да и вообще хоть как-либо) посчитать общее число прецедентов?
приведённое ПО считает лишь число покрытых методов, а это разные вещи.

да, можете считать, что придираюсь к терминологии.
0
eisernWolf #
Ты лучше расскажі, что ты понімаешь под «прецедентом». :)
0
zerkms #
насколько я помню, именно к. бек в своей книге о тдд рассказывал, что 100% покрытие тестами это охват всех сочетаний аргументов тестируемых объектов (методоф, функций). под прецедентом я понимаю как раз такой единичный набор аргументов (тесткейс).
исходя из сказанного выше — 100% покрытие практически недостижимо и количество прецедентов (тесткейсов) практически не поддаётся измерению (по крайней мере автоматическими методами).

ps: всё вышесказанное опирается на остаточные воспоминания от прочтения, пруфлинков не будет. если вы считаете иначе — спорить не буду. :-)
0
eisernWolf #
Колічество тест-кейсов завісіт от разработчіка. Кент как раз об этом і пішет. Прі этом многіе тест-кейсы рождаются уже в процессе разработкі прі аналізе code coverage. В VS 2008 она подсвечівает непокрытые участкі кода, і ты думаешь, как іх покрыть. Еслі тебе покажется, что это імеет хоть какой-нібудь смысл.

>>100% покрытие практически недостижимо и количество прецедентов (тесткейсов) практически не поддаётся измерению

В общем случае да. Я могу достигнуть 100% code coverage, тем не менее, все возможные діапазоны значеній параметров не будут перекрыты.

Поэтому вывод: я не поддержіваю работу «на ціфры». Эті метрікі могут лішь помочь прі составленіі тестов, но 100% вовсе не означает, что у вас там все впорядке. :) При определенном стечении обстоятельств можете получить результат, отличный от ожидаемого. Поэтому «подумать головой» еще никто не отменял. :) Особенно, чтобы не было случаев описанных выше по топику, мол, у нас тут куча тестов, а ничего не работает. :)
0
korchasa #
Код коду рознь. Есть много ситуаций, когда нет смысла увеличивать стоимость кода, даже написанием unit тестов, а уж тем более TDD.
+1
Denis_in_ua #
ИМХО, тесты дописать никогда не поздно. Бывают старые проекты без тестов, так и что? Бросать их на произвол судьбы?
0
VasilioRuzanni #
Нет, конечно, не бросать. Если нужно развивать проект, который содержит legacy-код, есть свои методики рефакторинга и постепенного покрытия тестами. Это отдельная большая тема, о ней писал Фаулер в одной из своих статей и думаю в ближайшем будущем создать топик отдельно на эту тему.
Там же становится понятно, почему быстрее и дешевле писать тесты сразу.
Впрочем, простое понимание TDD отвечает на этот вопрос (как бы «просто» это ни звучало, мы шли к этому почти год с командой!).
+3
shai_xylyd #
Писать тесты это здорово. Сейчас без них не могу работать, но раньше помню, что понимал, что тесты это хорошо, но никак не мог начать их писать. Помогло, когда я придумал отказался от создания исполняемой программы в первую очередь и писать весь код в виде библиотек, а запуск проводить с помощью тестов. Мне это помогло.
0
PixoiD #
А как на счет тестирование javascript? Что в нем то нужно тестировать, поведение HTML? Вот про это бы написали знающие люди.
+2
ya_goshka #
+2
VasilioRuzanni #
Есть еще BadBoy, и вместе с Selenium это средства функционального тестирования. Впрочем, разница в том, что в отличие от TDD и юнит-тестов, функциональное тестирование относится скорее к приемочному, а не является способом разработки. Однако, то, что люди используют и понимают необходимость в таких вещах, вызывает уважение, поскольку, видимо, достигли высокого профессионального уровня и заботятся о качестве своей работы.
+4
malkolm #
Как давно вы его применяете, что в таком восторге?
0
eisernWolf #
«Я прослышал про TDD наверное году в 2004 или 2005-м. Применять начал с 2006-го. » (с)
+1
RayZ #
Сумашествие. :) Я один не знаю, как расшифровывается ТДД?
+2
malkolm #
Test Driven Development
0
RayZ #
Спасибо.
+1
einzam #
Наверное test driven develompent
=)
Разработка на основе тестирования=)

+19
khizhaster #
Похоже на секту какую-то :)
— Да-да, я тоже начал это использовать и это чудо!
— Оооо! А мы написали это впервые и вместе кайфовали!
— Да, братья, делайте и не бойтесь! ОНО позаботится о вас!
+3
Denis_in_ua #
Ты принят, брат!
+1
developer #
Листовки скоро будут?
+2
dema #
А как тестируете работу с базой?
+1
slayerhabr #
+2
VasilioRuzanni #
Зря вас минусуют, ибо вопрос дельный.

Для этого есть 2 способа:
1. Тестирование самого приложения, как если бы оно работало с базой, но не подключая реальную базу, а только имитируя ее поведение с помощью так называемых mock-объектов. Это сильно упрощает жизнь разработчикам, так как не требуется постоянное обращение к медленному механизму, такому как СУБД, чтобы прогнать весь набор тестов.

2. Тестирование в стиле «а что если там будет реальная база». Такое тестирование тоже бывает нужно и оно называется интеграционное тестирование. Хотя юнит-тесты вполне описывают поведение системы с mock-объектом базы, на практике могут встретиться некие специфичные нюансы, и возникнуть они могут только при работе с реальной базой. К этому надо быть готовым и писать интеграционные тесты. Важно отметить, что интеграционные тесты не тестируют поведение (!), то есть они не дублируют юнит-тесты с mock-объектами, только заменяя «моки» реальной базой или файлом. Вовсе нет. Они как раз проверяют то, как поведение системы изменяется или не изменяется с возникновением специфики реальной субд.
0
dema #
Я, когда последний раз пробовал писать юнит-тесты для web-приложения, замучался писать mock'и и бросил это дело. Есть ли смысл тестировать простые операции с базой? Т.е., к примеру, метод просто сохраняет java объект в базу с помощью hibernate, попутно выставляя 1-2 параметра. Или такие простые вещи лучше не тестировать?

Писал на java, использовал easymock и jmock. Второй пункт смотрел, но не пробовал, в java для этого есть dbUnit.
+2
VasilioRuzanni #
Попробуйте тестирование состояний вместо тестирования поведений (тогда нельзя будет использовать моки, но этот способ чуть проще).

А насчет того, что нужно тестировать, а что нет — вам нужно тестировать поведение или состояние своих объектов (классов и их методов), а не пытаться тестировать внешние механизмы. Максимум — интеграционное тестирование внешних механизмов в работе с вашими.

Например, ваш метод, просто сохраняющий объект в базу с помощью Hibernate. Это метод вашего объекта (часть модели системы). Даже если он просто сохраняет, нам надо быть уверенным в том, что все сохранилось (причем с нужными значениями), так как другие части системы могут зависеть от этого добавления и вести себя по-разному в зависимости от того, добавилось ли в действительности.
Казалось бы — есть уверенность, что добавится, ведь это одна строчка…

Но! Допустим, через 2 недели появился запрос на изменение этой части кода. Внесение изменений в код вызвало то, что вдруг перестали работать всплывающие уведомления, кнопка добавления на интерфейсе и еще что-нибудь. По идее, можно было начать копать «сверху-вниз», проверить и кнопку, и уведомления и так далее, пока не дойдем до этого самого механизма добавления, который, как (к примеру) оказалось блокирует какое-то из наших недавних нововведений. Мы исправляем ошибку и радуемся.
Но разница в том, что если у нас есть тесты, мы запускаем их (нужную часть) и сразу видим, что во всем Fixture не работает именно наш механизм записи объекта в базу (чего не было в предыдущей ревизии), что сразу наталкивает на мысль посмотреть именно туда, и в итоге экономит кучу времени в поиске ошибок во время этих change-request'ов.

И да, такие простые вещи нужно тестировать, но не «для галочки», как считают многие, а по вышеописанной мною причине.
+1
korchasa #
Вот еще ссылочка, для общего ознакомления: wiki.agiledev.ru/doku.php?id=tdd:proper_mocks_usage

Статья, в том числе, основана на собственных шишках, а потому честная.
0
eisernWolf #
DDD
Соррі, распісывать сейчас времені нету. Спасібо VasilioRuzanni за поддержку. :)
+1
AxisPod #
Основная проблема, что работодатели в основном считают это пустой тратой времени. Надо быстро все сделать и им не важна скорость, им важен результат. А на TDD по началу времени надо потратить больше, а то что в будущем это приведет к экономии времени, на это работодатель не смотрит.
+1
malkolm #
Аргументируйте работодателю, зачем это нужно. Я вот тоже в свое время не знал зачем к мотоциклу отец две стальные дуги прикрутил. Пока пару раз не навернулся и они не спасли мне ноги, которые в результате не были прижаты к асфальту двигателем. Если бы он мне заранее объяснил свою мотивацию, я бы проверял их каждый раз когда на мотоцикл садился.
+2
joedm #
Безусловно, при рефакторинге юнит-тесты — незаменимая вещь, но при «первичной» разработке с применением TDD возможна ситуация, в которой «все работает, но ничего не работает», а именно: тесты не проваливаются, но в целом система не работает, хотя уже должна ;) TDD — это крайность, а все хорошо в меру. На мой взгляд, более правильный подход: пишется код, проверяется работоспособность вручную, потом (но без длительных отсрочек) на эту фичу пишуются тесты, причем 100% покрытие кода не требуется. Позже, если вдруг возникают баги, дописывается тест, воспроизводящий этот баг, и только потом баг фиксится (тоже самое делается, если «закопались» в дебаггере). Этот подход экономит время на разработку, т.к. отсутствует избыточность в виде тестов, которые в 99% случаев не провалятся, но требуют времени на написание.

Да, и плюс один к хабраюзеру khizhaster ;)
0
slayerhabr #
имхо иногда полезно написать тест еще в момент проектирования, до написания кода, тогда четко представляешь, что должно быть на выходе + готовый тест
0
joedm #
это нельзя ссчитать тестом. ;)
+1
mace #
Полностью согласен. У нас на проекте применяется именно такой подход.
+1
r4ge #
Вообще то у TDD — есть антипаттерны, они предостерегают от подобных ситуаций.
+1
eisernWolf #
Самое характерное, что они влияют и на дизайн классов при этом. Положительно влияют. Тот же god object… Очень часто в коде другіх разработчіков можно встретіть такіе «всезнающие» об'екты.
0
malkolm #
В общем все хорошо в меру :)
0
VasilioRuzanni #
Нет, не согласен.
TDD, как я уже упоминал в каменте выше, не способ тестирования, а способ разработки.
TDD — это не крайность, если так считаете, аргументируйте в чем именно.

0
VasilioRuzanni #
Не дописал, а камент отправился.

> с применением TDD возможна ситуация, в которой «все работает, но ничего не работает»
Нет, TDD тут ровным счетом ни при чем. Такая ситуация может быть и без TDD. А если у вас " тесты не проваливаются, но в целом система не работает, хотя уже должна", значит у вас, вероятно, тесты проверяют не то, что нужно или не полностью (такое обычно бывает, когда люди пытаются сначала писать код, а потом тесты).
–2
joedm #
Читайте классиков: «к пуговицам претензии есть?»
У нас неоднократно была такая ситуация. TDD, ja-ja, крутизна немеряная, 100% покрытие. Казалось бы, все замечательно, только в целом оно нифига не работает.
+3
VasilioRuzanni #
Конкретнее, plz.
Почему не работает? Что именно там не работало. Давайте рассмотрим на примере. Я готов аргументировать свою точку зрения полностью.
TDD «просто потому что круто и модно» работать не будет. Надо точно осознавать в чем и как оно может помочь.

P.S. Стопроцентное покрытие — на практике встречается краааааайне редко. И да, если стопроцентное покрытие правильно написанными тестами — ну просто не может не работать. Ведь тесты — это не что-то эдакое, они как раз и проверяют работоспособность.

Как пример, возьмем другую, смежную область.
Представьте, вот что вы как человек из QA-отдела проверяете работоспособность какой-нибудь системы — проверили, по вашему мнению все работает и соответствует спецификации. Но заказчик говорит, что «у нас ничего не работает». Где ошибка? Либо заказчик предоставил неверные спецификации (не соответствующие действительности его же бизнеса и требованиям) или же тестирование было неверным, проверялись не те аспекты, или проверялись не полностью.
0
ItGold #
Как ни странно, но я знаю ответ на этот вопрос, хоть и не знаком с данным товарищем.
Не работает, потому что тесты у них нифига не тестируют, да и написаны они, только ради галочки, чтобы похвалиться друг перед другом, мол, у нас тесты есть. Про 100% покрытие видимо опять же, для красивого словца упомянуто.
+1
VasilioRuzanni #
И еще. «потом (но без длительных отсрочек) на эту фичу пишуются тесты».
Вот уж где-где, а вот тут всегда будут «длительные отсрочки» :) Программистам нужно ставить более конкретные условия работы (например, TDD как правило), а не размывать их неопределенностью временных рамок.
+1
VasilioRuzanni #
> В 99% случаев не провалятся.
Забавно, вы действительно думаете, что все и всегда пишут на 99% качественный код?
+1
VasilioRuzanni #
Хотелось бы, кроме минуса, услышать контр-аргумент. Спасибо.
0
eisernWolf #
Многие на это не способны. А вот безудержные шаловливые ручонки деть некуда. :)
0
joedm #
Причем тут? Читайте внимательнее исходный комментарий. ;)
0
VasilioRuzanni #
Да я вроде правильно понял. Поправьте, если нет.

"… в виде тестов, которые в 99% случаев не провалятся..."
подразумевает, что в 99% случаев написан априори качественный и всесторонне рабочий код, не требующий работы с дебаггером. Или нет?

0
joedm #
Нет. Подразумевается, что код настолько прост, что тесты его тривиальны и нужны только для «галочки» в виде 100% покрытия. Например, getter for private field.
+2
VasilioRuzanni #
«Мы просто не верим, что после того, как я перелопатил все классы попутно упрощая дизайн, оно по-прежнему работает!!!»
Вот если бы каждый разработчик это прочувствовал, то куда большее количество людей начало бы использовать TDD :)
+2
joedm #
1. TDD тут ни при чем. Если код достаточно покрыт юнит-тестами, то рефаторинг дается ровно так же хорошо.
2. Если надо часто «лопатить классы», а также «трогать сколько угодно», то рекомендую сменить вид деятельности или уволить архитектора, т.к. у вас 100% bad design, и тут никакое TDD не поможет.
0
VasilioRuzanni #
Ну, скажем так, суть TDD в том, что тесты порождают код, а не код — тесты.
Дело в том, что именно тесты определяют, надо ли писать тот или иной код. Это, в числе прочего, еще и позволяет не реализовывать излишний функционал.

По второму пункту — немножко перефразируем — странно, что вам НЕ надо часто «лопатить классы» или «трогать сколько угодно». Ничто не создается сразу — функционал любой системы так или иначе на практике попадает под беспощадный меч change request'ов. Если нет — вы работаете с идеальными или несуществующими заказчиками :)
В частности, я говорю о том, что TDD используется при адаптивном подходе (Agile), когда нужно получить «минимальную рабочую вещь», а не реализовывать систему всю сразу (что вообще невозможно, т.к. предпочтения и нюансы всегда меняются по ходу дела).
–1
joedm #
Я знаю, в чем суть TDD :-) Повторяю пример: я написал тест для одной «фичи», написал под него код. 100% нужный и неизлишний. Пишу второй тест, для второй «фичи», хочу сделать reuse кода, написаного для первого теста. Имею право? Или копи-паста рулит? Так вот, reuse не получается, матерюсь, переписываю, первый тест отваливается. И так постоянно.
Метод TDD слеп, как котенок, он не позволяет видеть систему в целом.
0
VasilioRuzanni #
Ну, скажем так, Reuse и TDD напрямую не связаны. Не надо списывать на тесты то, что вы построили модуль системы, который слишком связан со всем остальным (кстати, интересно, как вы его полноценно протестировали :). Это проблемы архитектуры, а не тестов. Тесты не избавляют от необходимости понимать, как правильно выстроить программную архитектуру и сделать отдельные компоненты как можно слабее связанными.

P.S. Можно пример кода, чтобы не быть голословными, а разобрать все на примере?
–2
joedm #
Конечно, они не связаны. Вы можете сколько угодно теоретизировать, но есть объективная практика, которая доказывает, что такой подход неэффективен и тратит кучу времени.
0
VasilioRuzanni #
Нет. Это не аргумент. Нет никакой объективной практики, пока не будет живых примеров, которые ясно и четко показывают неэффективность подхода.

P.S. При утверждении, что я теоретизирую, также хотелось бы ссылку на факты.
Я попросил пример, после чего, не предоставив его, меня же «обвинили» в теоретизации.
0
efix #
непонял, реюс какого кода ты делаешь: тестового или приложения?
0
joedm #
кода, написанного для того, чтобы выполнялся тест.
+2
efix #
Согласен с предыдущим оратором. Трудно тут что-либо сказать без живого примера. То, как ты это описываешь для меня выглядит как будто тест неправильно написан.
С одной стороны если менялись интерфейсы, то естесственно должны быть подправлены и тесты.
С другой стороны, если было просто повторное использование кода без рефакторинга, то как может после этого провалиться тест?
Если живой пример достаточно объемен, может приведешь что-нибудь утрированное, но отражающее суть проблемы?
0
joedm #
Не менялись интерфейсы. Смысл в том, что при написании конкретного кода под конкретный тест не задумываешься о том, что этот же код с изменениями может использоваться и для выполнения другого теста. Проблема в том, что изменения в большинстве случаев оказываются значительными и повторными. Понятно, что для 'hello world' или там формочки логина (это мне подсказали ;) ) все тривиально и «ну не может не работать».
+1
korchasa #
И не надо задумываться. Заранее думать вообще вредно, т.к. архитектура получается сложнее там, где сложность, возможно, никогда не понадобиться. Проблема, того, что код под новые требования ломает код предыдущих, все равно непонятна. Как вариант — вы запускаете тесты слишком редко. Но это «пальцем в небо».
–1
joedm #
Ясно, monkey see — monkey do. Если когда-нибудь придется нанимать программистов, то приверженцев TDD буду гнать поганой метлой, уж извините…
+1
eisernWolf #
… к нам в команду — отлічнейшій подход между прочім! :)
+2
korchasa #
good enough это вообще отдельная тема, не имеющая отношения к TDD, требования должны поступать в формализованном виде. И если есть какие-то «вот тут захотим расширить», то они должны приходить к программисту готовыми, а не придумываться им самим. Поддерживать сложные решения (а гибкость порождает усложнение) всегда дороже. KISS и YAGNI пока никто не отменял.
0
VasilioRuzanni #
А bad design — это когда классы в принципе построены так, что их нельзя «перелопатить», сделать их mock-объекты, или у них слишком много прямых зависимостей и так далее.
0
VasilioRuzanni #
Для тех, кто еще не пробовал эту технику — советую попробовать. Если уж даже Microsoft, Adobe и многие другие софтверные компании начали активно использовать это, стоит как минимум попытаться понять — почему.
0
joedm #
Я пробовал. В случае pairing тот, кто не за клавиатурой, работает исключительно syntax checker-ом. ;) ведь могзи у всех поразному устроены, а написать самому — быстрее, чем объяснить другому то, что ты сейчас собираешься сделать. В общем, ничего интересного, кроме траты времени. Вот когда научатся объединять разумы, тогда приходите, попробуем еще раз. ;)
В случае TDD имеем проблемы с постоянным переписыванием кода: написали тест, написали код, написали другой тест, стали писать код, а тут выясняется, что код кривой или хочется сделать reuse, а не получается. Начинаем переписывать, но ведь ничего страшного, у нас же есть тесты! Ооо, не беда, что n тестов отвалились, ща пофиксим, мир-дружба-жевачка! «И так семь раз». ;) В итоге тратится ПРОРВА (это не капс, это я шифт жму (с) ) времени, а выход готового с гулькин…. Практика показывает, что эффективнее написать код, протестировать вручную, написать юнит-тесты и выпустить конечный продукт. Если потом где-то и стрельнет, то это быстренько фиксится при помощи написания теста (чтобы потом не допустить регресса).
0
VasilioRuzanni #
Регрессионное тестирование всяко надо проводить.

Сказанное вами во всем контексте говорит о неправильном понимании и использовании TDD. Однако, спорить по этому поводу я не хочу. Особенно про pair-программинг.

Даже на примере:
«написали тест, написали код, написали другой тест, стали писать код, а тут выясняется, что код кривой или хочется сделать reuse, а не получается».
Зачем вы стали писать код после первого теста, когда даже что они пригодится в таком виде, поскольку не был проверен другими тест-кейсами. Разумеется, такой подход просто пожирает время. Оптимально — выявить максимум тестовых ситуаций (исходя напрямую из требований к продукту), и написать код один раз.
Рефакторинг — отдельная тема. Он тоже не проводится «просто потому что должен».
0
VasilioRuzanni #
Ошибочка:

конечно же не «когда даже что они пригодится в таком виде, поскольку не был проверен другими тест-кейсами», а

когда даже не уверены, что он пригодится в таком виде, поскольку не был проверен другими тест-кейсами
+1
VasilioRuzanni #
Еще нужно напомнить, что TDD ведет к другой, не менее прекрасной командной методике — CI (Continuous Integration) или постоянной интеграции.
А также, если углубляться в тему, есть смысл отписать разницу подходов — тестирование состояний и тестирование поведений. Но, разумеется, это уже тема другой статьи.
+1
eisernWolf #
СС — імеется. BDD / TDD — хорошая тема. :)
blogs.gotdotnet.ru/personal/eisernwolf/PermaLink.aspx?guid=ff008ea9-211a-4a7f-800f-bed238a773c1
0
VasilioRuzanni #
Да, мы кстати тоже на .NET TDD осваивали и используем.
0
efix #
Расскажите лучше сколько человек у вас в команде, а так же кто и как инициировал переход на другой процесс разработки?
0
malkolm #
Судя по всему их двое
0
efix #
двое — это автор поста и Василио? :)
0
eisernWolf #
Двое. По обоюдному согласию.
0
Goodkat #
а как это использовать для php/javascript?
0
VasilioRuzanni #
Точно также, как и для всего другого. Везде есть xUnit-фреймворки (есть и jsUnit, и PHPUnit), и Test-Runner'ы для них, так что проблем с этим нет. Весь вопрос только в освоении подхода.
0
Goodkat #
ну я это и имел ввиду
думал, может кто кинет в меня ссылкой на русскую статью
+1
eisernWolf #
См. в сообществе agiledev.ru/.
0
VasilioRuzanni #
Опередили меня чуток.
0
VasilioRuzanni #
Да, конечно. Вот, пожалуйста, целый раздел на Agiledev. Как раз на примере PHP.
0
Jan_May #
При всём уважении к TDD, данный пост с комментариями VasilioRuzanni больше смахивает на рекламную листовку, или, как отмечали выше, на зазыв в какую-то секту.

Хотелось бы более детального обзора, с реальными примерами из жизни.
0
eisernWolf #
Ну это всего лишь постановочный пост в новом блоге. :)
0
VasilioRuzanni #
Почитайте комментарии, и укажите, plz, где они похожи на рекламную листовку.
Я ЗА эту тему, так как думаю, многим стоит хотя бы попробовать работать в таком режиме.
И без какого-либо фанатизма и сектизма, я знаю, что такое Agile на практике и аргументирую любое свое мнение.

Сам также за то, чтобы разбирать на конкретных примерах, ибо получаются споры, как выше с товарищем joedm, несколько беспредметные и чересчур «теоретические».
–1
joedm #
Пример из практики дать не могу ибо НДА-с. ;) А синтетический абстрактно-конкретный сочинять ломает — есть дела и поважнее.
0
efix #
что такое НДА?
0
joedm #
Non-Disclosure Agreement.
+1
VasilioRuzanni #
Ну вот, к сожалению, как только потребовались твердые аргументы, на нашем пути возникают NDA и важные дела. Ну что ж, спорить не буду, вполне возможно, что так оно и есть.
0
joedm #
Ох… ну вот вам упрощенный абстрактно-конкретный пример:
Надо подвинуть объект 1 из точки А в точку Б. Нет проблем, пишем тест, пишем код. Работает, все счастливы. Теперь надо подвинуть объект 1 из т. Б в т. А. Нет проблем, пишем тест, пишем код. Работает, все счастливы-2. Теперь существует объект 2 и надо подвинуть объект 1 из любой точки в точку В, при этом учитывая положение объекта 1. Пишем тест, пишем код. Понимаем, что копипаста. Начинаем переделывать код и п.1 и п.2. Тесты 1 и 2 начинают проваливаться. Тратим уйму времени на то, чтобы заставить заработать предыдущие два теста. Сделать бы сразу как надо, но TDD нам не позволяет этого — нельзя же думать наперед?
0
VasilioRuzanni #
Ну этот пример — не пример*, но думаю, у нас еще будет возможность поспорить на эту тему.

* Пример не содержит требований к точкам, А, Б и любой другой и информации об их различии (если они отличаются только координатами — это объекты одного и того же класса).
И непонятно, что означает «при этом учитывая положение объекта 1». Что это? Учитывая его координаты? Учитывая то, из какой точки он движется? Или может, в какую точку движется?
Так что все выводы в примере — такие, «какие пожелаются». Надо рассматривать на реальном примере.
0
korchasa #
Объект может существовать без положения?
0
Nakilon #
А я сначала прочел «TTD» и на пару секунд приятно удивился ..))
0
efix #
что такое TTD?
+1
dema #
Transport Tycon Deluxe?? :)
0
andry #
эмоциональный пост, однобокий. Очень уж мне не вериться, что не было никаких проблем. Все так с нуля, без опыта сразу и запохало, и у всех настало счастье и озарение!?
0
eisernWolf #
Я прослышал про TDD наверное году в 2004 или 2005-м. Применять начал с 2006-го.
0
rg_software #
Хотя к TDD в целом отношусь с симпатией, вот у меня лично никак не получается полноценно перейти на него.
Думается, что в целом TDD прекрасно работает, если надо написать что-то вроде библиотеки классов.

Но возникают траблы, если тестируем GUI (ну да, паттерн MVC, модель проверяем, но представление остаётся без проверки).

Ещё хуже, когда пишешь довольно сложный алгоритм (допустим, множество путей исполнения в зависимости от множества параметров). В этом случае получается, что сложность теста сравнима со сложностью алгоритма, и сочиняя тест, можно так же легко запутаться.

При этом класс не библиотечный, а «разовый», и нет особого желания «полировать» его, зная, что дальше текущего проекта жить он не будет.
+1
VasilioRuzanni #
«Ещё хуже, когда пишешь довольно сложный алгоритм (допустим, множество путей исполнения в зависимости от множества параметров). В этом случае получается, что сложность теста сравнима со сложностью алгоритма, и сочиняя тест, можно так же легко запутаться.»

Неверно, тест ни в коем случае не должен быть сложным, вернее, не должен быть сложнее алгоритма. Сложные алгоритмы на практике никогда не тестируются одним тестом. Для каждого из условий, как минимум, отдельный тест. Сочиняя тест, запутаться не проще, чем при написании кода. Если вы понимаете задачу, которую код должен решить — вы напишете тест.

«При этом класс не библиотечный, а «разовый», и нет особого желания «полировать» его, зная, что дальше текущего проекта жить он не будет.»

Тесты никак не связаны с переиспользованием. Вернее связаны, но только в положительном ключе — можно без страха что-либо сломать переносить разработки от проекта к проекту.
+1
r4ge #
Если пишите под c#, то там есть nunitforms, вполне себе удобная вещь.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.