Целесообразность unit-тестов

syfisher

TDD infected!!
Я еще раз просмотрел "Refactoring: Improving the Design of Existing Code" и не вижу в нем подтверждения этого тезиса.
В том-то и дело, что нигде это не указано явно. Примеры, которые там даны, слишком простые, для того, чтобы понять, о тестах какого уровня идет речь. Причем Фаулер ни разу не сказал, создает ли он новые test-case-ы при выделении классов или нет. Единственно на что я обратил внимание это "Первый шаг рефакторинга" первой главы этой книги (в русском издании).

Приступая к рефакторингу, я всегда начинаю с одного и того же: строю надежный набор тестов для перерабатываемой части кода.

....

Поскольку в результате statement возвращается строка, я создаю несколько клиентов с арендой каждым некскольких типов фильмов и генерирую строки отчетов. Далее сравниваю новые строки с контрольными, которые проверил вручную.
По-моему, это и есть описание приемочного теста перед рефакторингом. Это тест достаточно высокого уровня.

Что касается тестов, которые изпользуются при разработке через тестирование - это совсем другой уровень. Тесты здесь определяют то, как будет реализован тестируемый код, поэтому знаний о внутреннем состоянии намного больше (особенно при изоляции тестов).

Оговорюсь сразу, что это мое личное мнение и оно выработалось после 1,5 лет работы практически исключительно в стиле TDD. В своей практике я уже натыкался и на перегруженность тестов моками, и недостаточность тестирования, и на хрупкие тесты, которые слишком много знают о внутренностях тестируемого кода, так как изоляция была невозможна и проч. и проч.

Некоторые моменты до сих пор не ясны, поэтому мнение других людей особенно интересно.

P.S. Кстати, чужое мнение в деталях я так и не услышал... ;)
 

syfisher

TDD infected!!
У меня есть парочку вопросов, в принципе касающиеся темы:

1) Где кончается уровень модульных тестов, а где начинается уровень функциональных, а где приемочных? Касается немного изолирования, соответствия тестов реальности и т.д. Если у кого есть опыт работы с крупными приложениями, разрабатываемыми через тесты, думаю будет интересно обменяться опытом.

2) Продолжение темы про рефакторинг и тесты. Хочу разобрать пример, и рассмотреть его с точки зрения TDD и рефакторинга (встретил в рассылке TDD yahoogroups).

Если у кого есть желание пообщаться на эту тему - может быть заведем отдельные топики. Мне не хочется флеймить, хочется конструктивного разговора.
 

pachanga

Новичок
Автор оригинала: syfisher
У меня есть парочку вопросов, в принципе касающиеся темы:
Здесь на все твои вопросы есть ответы:
http://tap.testautomationpatterns.com:8080

-~{}~ 10.04.05 13:07:

Автор оригинала: syfisher
Тесты бывают различных уровней:
* web-тесты (приемочные)
* unit-тесты (модульные).
На самом деле не самая удачная классификация тестов, я бы сформулировал несколько иначе, итак в TDD тесты бывают 2-х уровней:
  • функциональные тесты(functional tests) - собственно с них начинается и заканчивается оформление требований заказчика к конечному продукту. В отличие от модульных тестов функциональные не принимают во внимание деталей реализации.

    В XP такие тесты называются тестами заказчика(customer tests).

    В прошлом функциональные тесты также называли приемочными(acceptance tests), однако от этой терминологии отказались в связи с тем, что заказчик теоретически обязан писать свои приемочные тесты после того, как все функциональные тесты сработали.

    Средств для написания функциональных тестов - превеликое множество. Скажем, для PHP существует прекрасная библиотека SimpleTest , помогающая проводить функциональное тестирование для Web приложений.

    Существуют также программные продукты, целью которых является облегчение написание спецификации для функционального тестирования. Для PHP из этой области скоро на горизонте появится Arbiter(от авторов SimpleTest)
  • модульные тесты(unit tests) - тесты, проверяющие некоторое узкоспециализированное поведение системы.

    Эти тесты не видны конечному заказчику или доменному эксперту. Обычно их начинают писать после оформления функциональных тестов.

    В XP такие тесты также называют programming tests, developer tests.

    Ну а говорить о том, сколько на свете есть xUnits, думаю не стоит :)

Обычно под эти две категории тем или иным образом подпадают мириады типов тестирования.
 

syfisher

TDD infected!!
Могу поделиться некоторыми мыслями насчет тестирования.

Если кратко то: из своего опыта я сделал такой вывод: функциональные тесты необходимы; они должны знать как можно меньше деталей тестируемых классов (только внешние последствия). Однако они имеют минимальное воздействие на дизайн. Хотя эти тесты желательно писать до кода, я бы не назвал эту деятельность разработкой через тестирование, так как design-решений при их написании - минимальное количество.

Pure TDD - это написание модульных тестов до кода и принятие дизайн-решений исходя из этих тестов.

Почему?

В течение нескольких месяцев подряд мне пришлось работать практически только на уровне одних классов и тестов для них. То есть соотношение 1 класс - 1 тест было для меня обычным. Это было чистое TDD, только подход не сверху вниз, а снизу вверх.

Совсем недавно мне пришлось сесть за реальный проект, построенный на наработках, сделанных в течение предыдущих месяцев. Не скажу, что это была очень простая задача, но особых сложностей также не возникнуло. То есть дизайн, полученный через TDD, почти устраивает меня.

При построении реального проекта уже пришлось перестроить тактику разработки на сверху вниз. Некоторые решения пришлось пересмотреть, особенно в части взаимодействия классов. В итоге я сделал для себя несколько выводов:

1) Если необходимо разработать систему и дизайн ее еще не определен, то есть, скорее всего, необходимы решения на уровне целых пакетов, то без TDD не обойтись. Здесь я пишу тесты на отдельные классы, широко использую моки, изоляцию, заглушки и все такое.

2) Приемочные тесты необходимы как воздух. Они могут быть очень простыми, но они нужны.

Очень часто сталкивался с ситуацией, когда приемочный тест говорил мне, что есть ошибка. Я проверял функциональность ручками и не находил ошибки. Поначалу я думаю, что приемочный тест неверный. Однако он не может быть неверный, на то он и приемочный. В итоге я каждый раз находил ошибки внутри проекта.

3) На достаточно крупные блоки классов необходимо писать тесты с минимальной степенью изоляции.

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

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

Такие тесты удобно иметь, когда решение какой-либо проблемы требует просто организации взаимодействия каких-либо конкретных объектов.

Эти тесты позволяют находить большинство проблем, связанных с реальным использованием классов из библиотеки, разработанных по TDD.

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

Можно даже сказать, это просто модульные тесты на классы-фасады (в большинстве случаев это так и есть), только выполненные без изолирования.

Данные тесты легко вписались в общую концепцию рефакторинга - "Рефакторинг не должен приводить к изменению тестов". Также легко следовать принципу о том, что тесты не должны вдаваться в детали реализации тестируемого кода.

Теперь к вопросу о целесообразности :)
Приемочные и функциональные тесты (более крупные, чем модульные, я называю их так) по объему намного меньше, писать их - одно удовольствие, они гораздо повышают уверенность в коде. Для их написания редко требуется особые знания паттернов, моков и т.д. То есть такие тесты могут писать разработчики любого уровня, даже начинающие.

Модульные тесты более низкого уровня, действительно, часто требуют переделок при рефакторинге, даже если зависимости между классами минимальные. Однако их главное назначение - определять дизайн, выявлять слабые места.
 

pachanga

Новичок
В ответ на http://phpclub.ru/talk/showthread.php?s=&threadid=67108&perpage=20&pagenumber=2

Автор оригинала: varan
По поводу TDD: мои ожидания не подтвердились. Очень много голословных утверждений без доказательств, которые не убеждают.
Из серии: с модульными тестами писать быстрее
Здесь я себе позволю процитировать очень уважаемого человеке в мире PHP TDD, Marcus Baker'a. Вот почему с тестами(в том числе и с модульными) разрабатывать быстрее:

* I don’t spend my time testing (one click of the mouse is all I need).
* I don’t spend my time deploying (one command line is all I need).
* I don’t spend time tracking project progress (one click of the mouse is all I need).
* I don’t spend time verifying code against requirements (one click of the mouse is all I need).
* I don’t spend my time documenting the code (the unit tests do that for me and they don’t lie).
* I don’t spend my time writing requirements docs (the acceptance tests do that for me and they don’t lie).

наследование классов устарело
Все это было сказано несколько в ином контексте: "классы с большой иерархией наследования очень плохо тестируются, поэтому предпочтительно заменять наследование делигированием".

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

, что тесты нужны даже для программ вычисляющих сумму 2+2 и т.д.
Ну зачем же так утрировать....

И вообще это напоминает какую-то секту: глаза горят, хотят всех заманить. Без обид, ОК?
Да без проблем, не любить TDD - это твое дело. Хотя...я думаю, прежде всего это наша вина, что некоторые вещи не смогли должным образом донести(но все же первый раз выступали, сделай нам скидку :))

А насчет секты ты прав - мы же TDD infected, еще всех позаражаем :)

Боюсь, теперь точно никогда не буду модульные тесты использовать.
Очень жаль такое слышать, хотя....никогда не говори никогда, поверь мне. Как только у тебя появится серьезный проект, ты еще не раз нас вспомнишь.

Для меня столь категоричное утверждение не использовать модульные тесты напоминает непонимаение определенного круга разработчиков целесообразности использования CVS подобной системы.

Если задуматься, то использование CVS также требует измененения менталитета разработчика, что порой происходит крайне болезнено.

Ярые враги CVS также любят утверждать, что разрабатывать дольше, следуя дисциплине commit/checkout/update, хотя на самом деле это очень недальнозоркое утверждение. Здесь вполне возможно провести аналогию: использование тестов - методология, требующая определенной дисциплины и менталитета разработчика, которая при разумном использовании приводит в порядок хаос разработки и ускоряет процесс доставки качественного продукта конечному потребителю. Не стоит ждать от тестирования мгновенных результатов, выгода проявляется в долгосрочной перспективе.

А пока желаю тебе веселого дебага! :)
 

syfisher

TDD infected!!
Ввиду того, что на конференции появилось много очень вопросов по моему докладу, хочу сделать небольшое дополнение. Общий смысл будет таков – необходимо воспринимать мой (да и Павла тоже) доклад именно в рамках TDD, а не как список тезисов правильного ООП. Может быть я поступил неправильно, что в самом начале под-темы называл выводы, а потом показывал, откуда они взялись. Многие кроме этих вывовов для себя ничего не уяснили и совершенно потеряли контекст доклада.

1) Психологический фактор в вопросе о целесообразности.

Можно опустить все факторы, которые говорят о том, что количество ошибок падает, их легче искать, что дизайн получается лучше и все такое. Но вот то, что общее настроение разработчика улучшается – это факт и очень важный. Не зря Павел начал свой доклад с этого. С TDD появляется уверенность, что твоя работа выполнена действительно на должном уровне, и все действительно работает. Именно это состояние называют Test Infected. Сейчас меня бросает в дрожь, если я не вижу зеленой полосы дольше 15 минут при разработке чего-либо. Уверенность в коде и в себе – это и есть болезнь тестами. Может мне не хватает слов, чтобы объяснить, это нужно испытать каждому на себе и сравнить свое состояние до и после. Я если пока не понятно – то как говорится, приходите, когда найдете настоящую работу.

2) TDD – это самый легкий способ находить места наиболее сильных зависимостей между классами.

Так уж повелось, что статические методы, наследование и смесь различных ролей в одном классе – самые явные признаки зависимостей, и тесты показывают это очень явно ростом размера фикстур и замедлением. Я не хотел сказать, что нужно отказываться от наследования. Вовсе нет. Пользуйтесь на здоровье. Но как только в иерархии появляются зависимости от внешних ресурсов – это признак того, что скоро иерархию придется ломать. То же самое касается и статических методов. Я кстати об этом говорил в самом начале своего второго доклада.

Еще я очень рекомендую прочитать вот эту статейку – в ней перечислены 11 принципов, которые лежат в основе объектной парадигмы и ООП вообще: http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfObjectOrientedDesign

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

-~{}~ 18.05.05 12:11:

3) Ну и наконец, я обещал многим книги и ссылки. Решил, что пока можно их выложить именно сюда.

Сначала книги:

* ВЕРЕВКА ДОСТАТОЧНОЙ ДЛИНЫ, ЧТОБЫ… ВЫСТРЕЛИТЬ СЕБЕ В НОГУ
Правила программирования на Си и Си++
Ален И. Голуб.
Как писать качественный код. Многие вещи спорны и уже устарели, но все равно книга
очень полезная.
Рекомендуется.

* Fowler - Refactoring_Improving the Design of Existing Code.
М. Фаулер - Рефакторинг. Есть на русском языке. У нас есть в печатном виде.
Рекомендую преобрести в личное пользование, благо сейчас она сильно подешевела.
Обязательно к прочтению.

* Приемы объектно-ориентированного проектирования: паттерны проектирования by Э.Гамма и др. (GoF).
обязательно к прочтению. У нас есть в печатном и электронном виде.

* М. Фаулер - Patterns of Enterprise Application Architecture. На русском уже есть перевод,
но я не знаю, как он называется. На books.ru по-любому есть. У нас есть в оригинале печатный вариант.
Обязательно к прочтению.

* Экстремальное программироваие - целая серия различных авторов, но пока хватит:
* Экстремальное программирование by Кент Бек.
* Экстремальное программирование: с первых шагов и до победного конца by Кен Ауэр, Рой Миллер.
Обе очень рекомендуются.

* Экстремальное программирование - разработка через тестирование. К.Бек.
Введение в автоматизированное модульное тестирование. Обязательно к прочтению.

* JUnit in Action - автора не помню. Одна из первых книг, которые мы читали про TDD. Очень доходчивые примеры. Очень рекомендуется, несмотря на то, что написана для Java.

* Working Effectively with Legacy Code
by M. Feathers – рефакторинг кода на пути к pure TDD. Очень рекомендуется для тех, у кого сложное наследие.

* JUnit Recipes by J.B.Rainsberger – сборник рецептов по написанию модульных тестов. Очень рекомендуется, хотя и для Java.

* Domain Driven Design Tackling Complexity In The Heart Of Software by Eric Evans - больше книга по бизнес-моделированию, однако очень ценная как сборник приеров использования шаблонов проектирования в разработке бизнес-проектов. Требует серьезных навыков ООП.Очень рекомендуется.

* Горький вкус Java. Брюс Тейт. Очень рекомендуется, особенно глава I и глава III. Введение в анти-паттерны. Несмотря на то, что написана для Java - применимо к любому другому языку.

* Pattern-Oriented Analysis and Design: Composing Patterns to Design Software Systems
by Sherif M. Yacoub, Hany H. Ammar. Ну это чтобы вообще крутым стать :) Очень рекомендуется.

* Object Design: Roles, Responsibilities, and Collaborations
by Rebecca Wirfs-Brock, Alan McKean - сам еще не читал. Говорят, что очень полезная в деле совершенствования ООП знаний.

Теперь ссылки:
http://www.sitepoint.com/forums/showthread.php?t=261656 – отдельная тема на Sitepoint.com, посвященная ссылкам на источники по TDD.
http://martinfowler.com/articles.html
http://www.objectmentor.com/resources/articleIndex
http://www.xprogramming.com/XP_links.htm
http://wact.sf.net
http://simpletest.sf.net
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Ну зачем же так утрировать....
Просто я спрашивал у вас, начиная с какого размера проекта (в человеко-часах) стоит использовать модульные тесты, получил ответ, что с любого.
Ну не могу я принять такой ответ! На мой взгляд, возможно есть проекты, где такие тесты нужны, например, где неправильная работа системы может вылиться в потерю очень серьёзных денег. Но тестировать простейшую гостевую, тестировать методы а ля set и get, да еще и эмулировать работу почтовой системы - это явный перебор.

Насчет наследования - видимо я на конференции неправильно понял. В принципе я тоже считаю, что слишком сложное наследование - это плохо, но и отказываться от него совсем тоже нельзя.

Я торжественно обещаю, что буду и дальше изучать вопросы TDD. Особенно меня волнуют вопросы затраченного времени. Может, приду к какому-то компромису, хрен знает. Но пока что я явно TDD disinfected :)
Кстати, не могли бы вы выложить в инет те книжки, которые у вас есть в электронном виде?
 

pachanga

Новичок
Автор оригинала: varan
Просто я спрашивал у вас, начиная с какого размера проекта (в человеко-часах) стоит использовать модульные тесты, получил ответ, что с любого.
Ну не могу я принять такой ответ!
Ладно, если у тебя проекты 5 человеко-минут, то можешь забыть о тестах как о страшном сне. Ты счастливый человек!

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

Но тестировать простейшую гостевую, тестировать методы а ля set и get,
Посмотри еще раз раздаточный материал, там сеттеры/геттеры тестировались не просто для галочки, этот тест позволил также произвести ранний рефакторинг и выделить вспомогательный тестовый метод, который используется далее.

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

да еще и эмулировать работу почтовой системы - это явный перебор.
А вот это очень непрофессиональное утверждение!

Каким образом ты тестируешь отправку писем? Ты каждый раз "прокликиваешь" десять форм, потом запускаешь почтовый клиент и проверяешь почту на предмет совпадения с некоторым текстом??? Как думаешь, сколько ты при этом теряешь денег(я использую твои рассуждения о деньгах)?

Я торжественно обещаю, что буду и дальше изучать вопросы TDD.
Ну хотя бы этим порадовал :)

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

  • тесты заставляют разработчика следовать принципу YAGNI - You Ain't Gonna Need It, т.е ты не будешь пытаться реализовать то, что на деле не потребуется. Тесты являются ранними и самыми строгими клиентами кода, выявляющими действительно необходимые прецеденты использования кода.
  • отлов ошибок в дебагере происходит однажды при первом запуске тестов, а не каждую итерацию разработки

А вот время требуемое для поддержки, рефакторинга, добавления новой функциональности уменьшится в разы.

Кстати, не могли бы вы выложить в инет те книжки, которые у вас есть в электронном виде?
А нам за это "ататай" не дадут? :) Как никак пиратство....
 

pachanga

Новичок
Ссылка в тему: http://blog.casey-sweat.us/img/phpt_tdd.zip

Это слайды доклада на тему TDD с конференции php|tropics, которая имела место на днях где-то в Мексике, известного в PHP мире разработчика Jason Sweat'а.

Очень доходчиво и с "мультиками" :)

P.S. надеемся в ближайшее время выложить свои слайды также в онлайн....
 
pachanga, вы обещали ссылки выложить и рекомендованную литературу. Можно прям здесь, думаю, всем полезно будет.
 

Mephistophel

Новичок
Тогда по емайлу
ага, и мне.
Уже с полгода пытаюсь проникнуться, но что-то все никак :(
То одно мешает, то другое.
В частности, то, что было названо мифом: отрефакторить систему, в которой больше 10 Мб кода я просто не предстваляю себе как... Вернее, предстваляю, но боюсь подумать о ресурсах, которые для этого потребуются.
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
А нам за это "ататай" не дадут? Как никак пиратство....
Ну раз они у вас уже есть, значит вы уже пираты :) Терять уже нечего :)
 

pachanga

Новичок
Автор оригинала: Mephistophel
В частности, то, что было названо мифом: отрефакторить систему, в которой больше 10 Мб кода я просто не предстваляю себе как...
Конечно, с "нахрапу" тут ничего не сделать, да и надо ли? Обычно рефакторингу подвергаются определенные части уже существующей системы(конечно же мы "фиксируем" себя при помощи тестов)

-~{}~ 18.05.05 13:50:

Автор оригинала: 2NetFly
pachanga, вы обещали ссылки выложить и рекомендованную литературу. Можно прям здесь, думаю, всем полезно будет.
Подожди, выше syfisher уже выложил довольно полный список литературы. Насчет прямых ссылок надо подумать, я конечно могу выложить их на публичный сервер, но как-то неудобно :) Слать же каждому на мыло нескольно утомительное занятие... Может, кто даст ftp аккаунт совсем левого сервера, чтобы не особо светиться?
 

syfisher

TDD infected!!
Автор оригинала: Mephistophel
В частности, то, что было названо мифом: отрефакторить систему, в которой больше 10 Мб кода я просто не предстваляю себе как... Вернее, предстваляю, но боюсь подумать о ресурсах, которые для этого потребуются.
Почитай M. Feathers про legacy code. Будет многое понятно. список книг смотри выше.
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Может, кто даст ftp аккаунт совсем левого сервера, чтобы не особо светиться?
Да зарегься на любом бесплатном хостинге, да и всё
 
Сверху