Как стать автором
Обновить

Комментарии 58

В проектах чуть сложнее самого простого, без TDD никуда. Даже и добавить нечего. Жаль что все этого понимают, особенно среди сайтостроителей.
Мы сейчас делаем проект, позволяющий строить схему переноса данных из Excel в систему документооборота (с последующим переносом данных). Я пытался применить TDD, но даже просто писать тесты для частей, связанных с GUI, Drag'N'Drop, объектной моделью Excel — это pain in the ass. Что уж говорить про Test Driven.

Вообще, [в рунете] очень мало материалов по применению TDD в сложных проектах. Но да, все говорят, что без него никуда.
Ну да а 3 связанных синглтона вообще невозможно теститровать :) в вашем случае помогут Moc объекты и отделение логики от UI ( посмотрите MVC или MVVM( если используете WPF).
В принципе можно, по крайне мере для Java, если модифицировать загрузчик и вместо синглтонов, не являющихся в текущем тесте тестовыми субъектами, подгружать поддельные классы, у которых будут с оригиналыными совпадать все доступные извне поля, методы в том числе и статические, их сигнатуры и имена пакетов.

Иногда это можно сделать даже без модификации загрузчика, когда синглтоны лежат, скажем, в разных jar-библиотеках. Такой подход используется, в библиотеке логгирования slf4j, в которой для того, перенаправить все вызовы к устаревшей, по их мнению, библиотеки commons-logging, они сделали полную эмуляцию доступных ее членов, с теми же сигнатурами как и в commons-logging.

Да и в рунете вообще практически нет нормальной информации ни о чем, что касается современной разработки, таки надо учить английский.
Читать на английском могу, но времени на чтение/понимание уходит ощутимо больше :(
Ну и пользы от чтения на языке оригинала обычно намного больше :) вообщем я свой выбор в этом плане сделал довольно давно :) + Чем больше читаешь, тем быстрее читаешь как банально бы это не звучало.
Ну и пользы от чтения на языке оригинала обычно намного больше

Ага! Так я и имел в виду оригинальные статьи на русском :) Перевод действительно часто оставляет желать.
Это, наверное, как с TDD, поначалу напрягает, а потом появляется больше возможностей. Хотя бы в использовании поиска, что уже немало. Английский я начал понимать в мануалах, только потом задумался о том, что было бы неплохо воспринимать всё это еще и на слух. Там помогают фильмы, но это уже оффтоп.
Все в ваших руках
Вы так вдохновляюще написали, что захотелось прямо сейчас начать писать с использованием TDD. Спасибо.
Мне как сноубордисту пример со сноубордом был очень кстати. Позволив понять весь процесс обучения TDD. Спасибо за статью.
так получилось, что TDD и сноуборд я осваивал одновременно. и там, и там делал это без инструктора — по книгам и видео-туториалам. и в TDD шишек набил, и на сноуборде плечо выбил… так что когда наткнулся на эту статью — как свои мысли прочитал:) потому, наверное, и решил сделать свой первый перевод. рад, что не мне одному она понравилась.
Эх… А мне сразу в горы захотелось поехать кататься и задвинуть весь программизм подальше к чертям вместе с TDD, DDD, BDD и.тп.! :-)
Спасибо за комментарий, но я это только перевел — внизу топика ссылка на оригинал.
Скрытая реклама K2 однако.
НЛО прилетело и опубликовало эту надпись здесь
Гораздо пороще написать тест, чем руками поднимать всю систему и проверять работоспособность новой функции или изменения. За счет этого будет значительная экономия времени при подходе TDD.
Хочу взобраться на гору TDD. Где найти инструктора?
Вы так вдохновляюще написали, что захотелось прямо сейчас покататься на сноуборде
вчера покатался в снежкоме… хоррррррошо!
сам хочу:) но пока нет снега — только TDD:)
TDD хорошо до тех пор, пока логика сравнима по объёму с тривиальным кодом, производящим сохранения/загрузку из базы данных и отсылку этих данных на клиент. Потому как в этом случае 80% тестов будут проверять либо прокси-функцию из 1-й строчки, либо проверять корректность SQL-запроса путём его многократного прогона на разных данных.
Как раз сохранение/загрузка в БД в модульных тестах никак не проверяется. Модульные тесты проверяют бизнес-логику и полностью игнорируют внешние ресурсы, такие как БД, сервисы и т.п.

В «больших» проектах бизнес-логика является основной частью системы, причем самой сложной. Поэтому написание на нее модульных тестов, которые автоматически запускаются хотя бы раз в день, является важной задачей. Возможно ваша система написана целиком на хранимых процедурах, ну тогда это есть проблема №1. Все, кто заказывают мои консультации, имеют на руках системы с бизнес-логикой в хранимых процедурах :)

> проверять корректность SQL-запроса путём его многократного прогона на разных данных

Зачем проверять корректность SQL-запроса? Он сам по себе ничего не несет. Значение имеет этот запрос в связке, например, с UI. Поэтому проблемы SQL-запроса будут отлавливаться интеграционными тестами (не модульными), которые проверяют работу системы, рассматривая ее, как черный ящик.

Более подробно я уже описывал habrahabr.ru/blogs/tdd/82842
На удивление, логика у нас не на хранимых процедурах =)

Однако, почему-то так получается, что unit-тесты достаточно быстро превращаются в integration-тесты. Возможно, это — последствия использования BDD (получаем: 1 задача — 1 набор тестов).
Тут ещё важно, чтобы «TDD» не превращалось в «BDD». Это когда с горы летит растущая лавина багов, а вы на сноуборде от неё уворачиваетесь. Можно, конечно, и финиша достичь, а можно ведь с размаху и в дерево вмазаться.
Аббревиатура BDD уже занята и B в ней вовсе не Bug ;-)
Ну я потому и взял в кавычки, а лучшей аббревиатуры и не придумалось. К сожалению порой это именно так и выглядит, и «Bug» сильно преобладает над «Behaviour»…
Подскажите, что почитать по TDD?
первой книгой должна стать «Экстремальное программирование: разработка через тестирование» Кента Бека.
также порекомендую «Эффективная работа с унаследованным кодом» Майкла Физерса
> первой книгой должна стать «Экстремальное программирование: разработка через тестирование» Кента Бека.
Осталось её найти. Почему-то «Питер» её с 2003 года не переиздавал.
«Growing Object-Oriented Software Guided by Tests» очень хорошая книга. Там есть примеры, как применять TDD для тестирования интерфейса и баз данных. На русском не видел, но английский язык там простой и хорошие небольшие по размерам понятные примеры.
Кстати, если кто-то пишет на Ruby On Rails, могу порекомендовать книгу: «Rails Testing Prescriptions», очень хорошо рассказывает о TDD. Автор поясняет на примерах зачем все это нужно. И постепенно раскрывает все тулзовины которые есть в рельсах для комфортного тестирования.
В книге «Экстремальное программирование: разработка через тестироваине» Кент Бек также проводит интересное сравнение: «Консервативные скалолазы придерживаются одного важного правила. У человека есть две руки и две ноги, всего четыре конечности, которыми он может цепляться за скалу. В любой момент времени по крайней мере три конечности должны быть сцеплены со скалой. Динамические перемещения, когда скалолаз перемещает с места на место одновременно две конечности, считаются очень опасными. Методика TDD в чистом виде подразумевает использование похожего принципа: в любой момент времени вы должны быть не дальше одного изменения от зеленой полосы.»
Не очень удачное сравнение. Без динамических перехватов невозможно пройти многие сложные трассы. Сейчас этого принципа разве что альпинисты придерживаются.
Похоже TDD становится новой мантрой разработки. Как например MVC до этого. Толпы людей повторяют MVC как заклинание, продолжая псиать огромные тонны логики в контроллере. Это не мешает им рассуждать о многослойной архитектуре и дискутировать на тему необходимости скорейшего введения примесей в php/java/etc

Тоже самое, похоже, начинает происходить с TDD.
Сам TDD — это не панацея ниразу. Люди которые писали толстые контролллеры — начнут писать к этим контроллерам тесты (которые почему-то будут называть «юниттестами»). Тесты будут такими же толстыми и сложными как сами контроллеры. Для работы тестов понадобится сложное окружение. В итоге — огромные потери времени. Которые чаще всего заканчиваются тем, что принимается решение отказаться от автотестов.

Тесты (покрытие тестами) — это хорошо, но на мой взгляд, гораздо важней чтобы архитектура проекта была пригодной для тестирования.
Зачастую это означает широкое использование DI, по возможности минимизация использования синглтонов. Так же бывает полезным разумное использование закона Деметра. Благодаря этому связность компонент падает. Сами компаненты становятся проще и можно легко и безболезненной писать простые и короткие тесты (юниттесты). (Дополнительный бонус — если проводить хотья бы немного упреждающее проектирование в интерфейсах — это позволит более эффективно распределять работу в том числе и на новых/временных участников команды).
Вобщем: если тесты пишутся тяжело и на них тратится много времени — верный знак того что в архитектуре у нас всё очень плохо.

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

P.S. Замечание о том что команды которые практиковали TDD быстрей адаптировались к изменениям, чем команды которые его не использовали — слабый аргумент в пользу фанатичного следования TDD. Адаптивность стала результатом, того что у команды с TDD была архитектура которая допускала юниттесты (см выше). Но — архитектура пригодная для юнитестирвоания может быть и вообще без юниттестов. Так что думаю TDD не является причиной адаптивности. Напротив — успешное использование TDD как и адаптивность к изменениям требований — являются следствием заложенной архитектуры.

P.P.S Фанатичное следование чему-либо — плохо)
НЛО прилетело и опубликовало эту надпись здесь
Полностью поддерживаю! Кстати, мощь DI тоже осознает все больше и больше народу, что не может не радовать.
TDD — один из инструментов адаптивной разработки, не более и не менее того. Причем тут фанатичность?

«Похоже TDD становится новой мантрой разработки.»
И это хорошо! Не нужно никакого фанатизма и крайностей, нужно просто применять методологию, понимая ее возможности.

«Люди которые писали толстые контролллеры — начнут писать к этим контроллерам тесты (которые почему-то будут называть «юниттестами»)»
Люди, которые вообще ничего не писали, так и не будут вообще ничего писать. Это не аргумент. Если человек не умеющий ездить на автомобиле, создает опасные ситуации на дорогах, отнюдь не означает, что никто не должен ездить, и «вообще это все тут сплошной фанатизм».
Блин. Хочется тренинг, в рамках которого с помощью TDD и других правоверных методик написалось бы что-нибудь сложнее калькулятора под зорким оком мастера.
Эх, скорей бы уже зима в Беларусь пришла…
TDD — очень гуд (и его производные в лице BDD).
Все ведущие софтверные компании мира применяют TDD — посему странно бывает смотреть на аргументы «ярых противников» — может быть «все не так то просто» и стоит как минимум попробовать?
Стоит предупредить — TDD вызывает привыкание и тяжелую зависимость! После его использования, код без тестов будет вызывать параноидальное недоверие :)
Извините, но это fail.

На простой чёткий вопрос «что насчет времени, необходимого при работе по этой методологии?» вылить тонну воды про какой-то там «сноубординг», банальщину про лучше день потерять, но за пять минут долететь и… ничего не ответить кроме «бороться и искать, найти ТDD и не сдаваться.».
По-моему был достаточно чёткий ответ: сначала время сильно увеличится, по мере освоения методики — уменьшится. Однако «простой и чёткий вопрос» не содержит ни слова об исходных данных: с чем надо сравнить TDD.
>>По-моему был достаточно чёткий ответ: сначала время сильно увеличится, по мере освоения методики — уменьшится

Этого нигде не написано. Единственное, что было по вопросу: сравненеие двух команд, и та, которая TDD? «подстраивалась под поставленные задачи… лучше».

Вы правы. Прямо так не написано. Я привёл сухой остаток.
Я всего-навсего хотел сказать, что ответы типа «это позволит вам подстраиваться лучше» щедро сдобреные водой отдают шаманством. И, в общем случае, свидетельствуют о том, что отвечающий не может ответить ничего конкретного. Это называется «доказательство тезиса заменяется его декларированием».
Упс, «отправка» нажалась.

>>Однако «простой и чёткий вопрос» не содержит ни слова об исходных данных: с чем надо сравнить TDD.

Наличие чего-нибуть сравнивают с его отсутствием если не указано иное. Это не очевидно?
Не очевидно. Вы полагаете, что вопрос был о создании корпоративной системы «от балды»? В таком случае добавление любой методики разработки ускорит работу.
Друзья, мы все читали книги про TDD и знаем как красиво написать калькулятор, используя эту мощную инженерную практику. Но, интересно другое. В рамках данной темы поделитесь, пожалуйста, своим практическим опытом (или конструктивными ссылками) применения TDD для Web-приложений? Для меня здесь не очевидным являются следующие аспекты:
1) В подавляющем большинстве, Web-проекты, которые мы разрабатываем, имеют минимальное количество бизнес-логики. В основном это CRUD-странички, т.е. Web-проекты состоят из логики доступа к данным (которая не тестируется Unit-тестами и заменяется Mock-объектами) и презентационной логики (которую, на мой взгляд, логичнее тестировать инструментами типа Selenium в рамках интеграционных UI-тестов). Т.е. получается, что оправданное покрытие проекта такого рода Unit-тестами будет минимальным. Например, мы сможем оправдать затраты времени на разработку Unit-теста для алгоритма расчета рейтинга пользователя, при этом, для остальных 99% кода Unit-тесты писать нет смысла, поскольку это просто логика извлечения и сохранения данных в БД. Не теряется ли при этом главный смысл и профиты TDD?
2) Я понимаю почему хорошо покрытие Unit-тестами презентационной логики CRUD-страниц для интерпретируемых языков программирования — они позволяют Вам обнаруживать синтаксические ошибки до выкладки кода на сервер. Наша компания использует компилируемые языки программирования — Java (JSF2) и C#(ASP.NET MVC2) и данный аспект мы отлавливаем без модульных тестов как непосредственно на машине разработчика, так и на сервере непрерывной интеграции. Чем еще может быть оправдано 90-100% покрытие кода Web-приложений модульными тестами для компилируемых языков программирования в Web-проектах?
3) В качестве важной особенности TDD был озвучен такой существенный аспект как продумывание и проектирование дизайна (API) приложения до начала написания кода его имплементации. В наших командах разработчиков мы используем методологию Scrum. На планировании, после того как мы уяснили суть задачи в бизнес-терминах, мы разбиваем задачу на ряд небольших технических подзадач, каждую из которых мы четко понимаем как делать и сколько это займет времени. Т.е. на этом этапе мы уже имеем достаточно низкоуровневый дизайн: знаем какие основные классы, методы и шаблоны мы должны разработать для реализации задачи. Имеет ли смысл при этом тратить время на разработку модульных тестов, которые, как Вы знаете, съедают практически столько же времени, сколько разработка собственно самого функционала?
4) Современные среды разработки дают нам инструменты, позволяющие проводить смелый рефакторинг кода, а наличие интеграционных тестов (например, Selenium) на ПК разработчика и на CI-сервере дает уверенность в том, что ничего точно не отвалилось в процессе. Так что данный аспект тоже является для меня не убедительным.

Поймите правильно, я вовсе не отпариваю ценность таких инженерных практик как TDD, где-то они просто незамеными. Например, в корпоративных и банковских приложениях со сложными workflow. А я просто пытаюсь обосновать для себя эффективность ее применения в моем конкретном случае при разработке Web-проектов средней сложности.

Если у кого-нибудь есть опыт и\или соображения на эту тему — буду рад конструктивному диалогу. Спасибо!
конечно, основной «хлеб» TDD — это бизнес-логика. очевидно, что она должна быть максимально покрыта тестами. TDD гарантирует это покрытие. другими словами, исключаются ситуации, когда разработчик, реализовав некоторую функциональность, решает ее не тестировать, оправдывая себя нехваткой времени, или откладывает написание теста на «когда-нибудь».
только при использовании API вы сможете ощутить всю прелесть, написанного вами кода, или увидеть его недостатки. TDD позволяет исправить ошибки API на самой ранней стадии.
ниже уже замечено, что хорошие тесты — это лучшая документация вашего кода. TDD — это гарантированное написание «документации» к вашей логике. а значит и более легкое сопровождение и поддержка в будущем.
Хотелось бы тоже добавить пару слов.
В свое время, еще на заре становления меня, как программиста, я озадачился ООП. Сначала даже не знал, что это за зверь такой! Потом понял, что это это и спросил у своего гораздо более опытного коллеги:
— А на ООП сложно писать?
— Ээээ… А в чем, по-твоему, отличие в коде между ООП и процедурным способом?
— Ну не знаю, все вокруг спорят стоит или не стоит писать с помощью ООП…
Каким же смешным этот вопрос выглядит для меня теперь. Это всего лишь вопрос изменения мышления, а не кода!
Теперь провожу параллель с TDD. Я вообще против покрытия кода на 100%, и вообще против гонки за покрытием ради покрытия. Если брать классическую MVC модель то тестировать нужно модели. И все. Если вы правильно пишете контроллер, то там нечего тестировать!
Простой пример.
Нужно сделать сайт копию твиттера. Ага. Значит у нас есть пользователи. Создаем класс User, а потом экземпляр этого класса. У нас есть Твит. Создаем класс Tweet, а потом экземпляр этого класса. Это очевидная стандартная линия рассуждений.
В ТДД нет разницы, просто мы «записываем» наши мысли.
Создаем класс User, а потом экземпляр этого класса. Возьмем и напишем первый тест, в котором будет создаваться экземпляр этого класса!
$user = new User();

Ведь в обоих случаях, в самом начале разработки мы пока точно не знаем какие будут свойства и методы этого класса. Указанный выше тест провалится: класс User не найден. Конечно! Мы ведь только сейчас придумали, что у нас будет этот класс! Давайте его создадим :) И Тест пройдет успешно!

Словом, ТДД для меня — это нифига не тестирование. Это именно разработка. Самое главное, что нужно уяснить: описывайте в тестах каждую свою мысль! Поверьте, все эти мысли есть у вас в голове, просто нужно научиться их ловить и «документировать»!
верное замечание, тесты — лучшая документация кода.
> $user = new User();

Отличный пример. Иногда у меня создается впечатление, что TDD придумали адепты динамической типизации, потому что им надоело ловить исключения во время выполнения.
Изумительное замечание! Плюсую.
В статье не хватает указания что TDD — это Test-Driven Development
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации