у меня возникло стойкое несогласие по некоторым моментам. Но поскольку сообщений было много и мнений было много, то анализ топиков, занял у меня некоторое время. Тем не менее, результат анализа перед вами.
Итак.
Высказывание "Если юнит-тестов нет, то программа не работает" — это догма. И как любая другая догма она является ложной, поскольку не учитывает многообразие реального мира.
Реальный мир для нас, небольшой компании, таков.
Проекты у нас 2-х видов. Долгие, развивающиеся в течение нескольких лет, там много своего кода, меняются они очень вяло. Тестов там тоже много, тем не менее время от времени всплывают сигналы о недостаточном покрытии функционала. Это нормально.
Есть и другие, и о них я буду дальше вести разговор.
Здесь программирование происходит в условиях перманентной нехватки времени. В таких условиях вопрос: "А где юнит-тесты?" звучит как издевательство. Очевидный ответ на этот вопрос: "А может вам ещё танец живота на столе станцевать?".
Другим аспектом является то, что в таких условиях основная часть времени времени выделяется на битву с окружением. Посмотрите в форум по Java. Подавляющее большинство вопросов: "Какого х### Hibernate | Struts | Jboss | AnotherCoolButComplexFramework делает не то, что я от него жду и как его добить". Проектирование сильно кренит в сторону "как сделать так, чтобы оно хорошо клеилось к окружению". Божьей помощью оказывается найти в инете работающий пример и разобраться, почему он-таки работает. Если такого примера нет, то приходится подбирать диаметр бубна, цвет ленточек и звук колокольчиков на нём. Процесс этот, как можно догадаться, недетерминированный. (Я не говорю, что библиотеки суть сплошной глюконат, я о том, что чтобы задействовать тот функционал, который находится в библиотеке, нужно следовать определённым правилам, и если нужных сценариев нет в доке и инете, то их (сценарии) придётся вырабатывать самому).
Создаваемое ПО имеет несколько особенностей: кусок "мясца" средних размеров (почему-то называемого заумным термином "Biznizz Lojig" '), и много кода взаимодействующего с окружением, библиотеками и фреймворками. Соотношение меняется от размера к размеру, но как правило "мясца" заметно меньше.
Худо-бедно победив окружение, делается мрачное внутри, но сносное снаружи ПО, с фичами, которые были жирно начёрканы в виде кривых квадратиков со стрелочками на листе формата A4. Эти фичи прорабатываются руками (такое тестирование обязательно) в виде определённого набора вариантов использования. Эти варианты должны проходить 100% гладко. Однако как только начинаются нестандартные варианты использования, корректная работа увы, не гарантируется. (вероятно только Билли Гейтс может позволить отшутиться на презентации BSoD'а, а для небольших компаний это всё равно что, извините, мордой в дерьмо — неприятно). Вдобавок об отодвигании сроков не может быть и речи.
Короче, такая недружественная практика по отношению к программистам при этом вполне себя оправдывает: продукт в рекордные сроки поставляются клиентам, клиенты кивают головой увидев что нужно, конкуренты курят бамбук. И только программисты слегка оправившись от пережитого "ужоса" понимают, что "ужос" скоро будет опять (очередная порция хотелок), поэтому надо взять рефакторинг и хотя бы причесать код. Опыт показывает, что код, написанный на большой скорости просто ужасен (низкий уровень обобщения, невнятные соглашения, большая избыточность, сильное сцепление), поэтому рефакторить надо.
Ладно, с условиями разобрались. Теперь перечислим факты о ЮТ, которые играют роль, но о которых не очень охотно говорят.
1. Писать ЮТ — рутина.
Кто не согласен, может попробовать выработать творческий подход к коду наподобие
На мой взгляд единственный элемент творчества здесь — это строковая константа.
Эта же причина вызывает острое желание, чтобы тесты более-менее автоматически генерировались, и контракты здесь выглядят как вариант, хотя мне нужны практические данные, чтобы делать какие-то выводы об их применимости. Тесты также можно генерировать из спецификаций, но создавать генератор — долго, да и спецификации витают в воздухе, нужны усилия для формализации.
Если отдать написание тестов в руки молодых специалистов — полученные тесты будут либо источником вечного веселья, либо вечной грусти (как повезёт, иногда бывает даже нормально). Другим опытным программистам разумеется отдавать тоже нельзя — не барское это дело. Вывод: никто кроме самого программиста нормальные тесты не сделает.
Опять же, по этой же причине (я имею ввиду "ЮТ-рутина") Java вызывает иногда ненависть, поскольку там невозможно достаточно просто написать обобщённый класс ClassX, и протестировать только этот обобщённый класс, а использовать Class1..3.
Написание обобщённого кода вызывает ощутимый оверхед, такой, что проще забить на это дело и не парить моск. Для тех, кто сомневается: представьте например, два больших, почти идентичных класса, причём они:
1. наследуют от одного абстрактного, абстрактный класс менять нельзя;
2. немного различаются статическими полями;
3. немного различаются обычными полями;
4. немного различаются внутренними классами (пусть они даже один интерфейс реализуют);
5. немного различаются набором методов и небольшими кусочками в методах, скажем таким образом
Как избавиться от дублирования? (Это очень даже реальный пример, два увесистых классика имели всего 43 диффа, дублирование мозолило глаз, но альтернативы? — плодить 43 оператора if, или ещё минимум 3 не самых простеньких класса. Плиз!).
Помнится не так давно пролетала ссылка (спасибо eao197) на весёлый текст "Execution in the Kingdom of Nouns", гиперболизм сплошной, но в общем и целом так и есть. (Справедливости ради нужно помянуть Java и хорошими словами, такими как "рефакторинг", "IDE", "reverse engeneering" и т.п.)
2. Написание ЮТ отнимает значительное время и требует внимания.
Этот факт в основном действует как красная тряпка, отвлекая от важных дел. Отвлекать от важных дел он перестанет только когда оно само (написание ЮТ) будет важным делом. А этого не будет никогда, впотому что задача "реализовать 10 архинужных фич к деду Лайну" важнее, чем "реализовать лишь 9 архинужных фич, но чтобы они работали в нестандартных условиях". Тремя словами это будет так: "worse is better".
Адепты TDD утверждают, что ЮТ неотделимы от непосредственно кода, и поэтому измерить соотношение потраченного времени отдельно на код и на тесты невозможно. Хотя очевидно, что это соотношение существует (на мой взгляд процент должен зависеть от типа проекта; чем проект дольше — тем меньше процент, а абсолютная величина больше), и доля тестов весьма ощутима.
Плюс необходимость переключать внимание с ЮТ на код и обратно — это разбрасывать шары, а потом их снова скрупулёзно собирать... (неплохая аналогия тов. Спольски). Как минимум — некомфортно. Фактически — расход заметного времени именно на переключение (общеизвестная статистика — вхождение "в поток" съедает 15 минут, умножаем это время на количество прерываний=переключений...).
3. Проверять код взаимодействующий с окружением скорее всего не имеет смысла.
(Такая нестрогая формулировка потому, что созданные примеры, показывающие как надо готовить библиотеки можно назвать интеграционными тестами, они выполняют роль поэтапных проверок при разрешении сложных ситуаций).
Итак, почему скорее не имеет смысла?
Такой код часто имеет следующую особенность: он работает только при грамотной конфигурации, наличия нужных джарок в нужных директориях, правильных переменных окружения и т.п. Примеров куча: деплоймент дескрипторы, plugin.xml, web.xml, struts-config.xml, yan.xml и так далее. Часто ошибки именно в неправильной конфигурации.
Поэтому пример, написанный один раз работающим, дальше кочует по другим частям программы слегка адаптируясь под контекст. Например, у нас есть сервер и для него конфиги просто копируются из одного места в другой будучи чуть-чуть подправленными под свои нужды. Написание данного конфига — это давно уже тема для внутрикорпоративного фольклора.
Так вот, чтобы протестировать код, нужно написать правильный конфиг, ну а дальше вы поняли... Рекурсия, как всегда, божественна.
4. Писать ЮТ до того как не написано ничего по теме — это распылять драгоценное время.
Как правило проблема окончательно проясняется после частичного её решения — увы, такова жизнь. Лучше взять листочек с карандашом и порисовать стрелочки (то есть заняться проектированием) или не откладывая в долгий ящик почитать туториал для используемых библиотек и поковыряться в примерах (таким образом получая важную информацию "снизу", необходимую для проектирования).
В данном случае уже работает выбор худшего из двух зол. Что хуже: ошибка в архитектуре или ошибка в работе метода? Я думаю, что как правило первое хуже.
Удар от отсутствия юнит-тестов смягчает наличие другого тестирования, типов и IDE. Вдобавок, если юнит-тесты будут, то не будет (или будет в недостаточном количестве) чего-то другого. Как всегда, бесплатный сыр соблазнительно качается на пружинке...
Подозреваю, что меня закидают тухлыми помидорами, но я рискну 5. Статическая типизация в сочетании с IDE работает удовлетворительно и без тестов.
Я отнюдь не противник динамически типизированных языков. В частности, мне очень интересен Erlang, и динамическая типизация в нём — то что доктор прописал. Действительно, взгляните на этот код:
Какие типы должны иметь "объекты" для функции allocate? Это очевидно. Например, первый аргумент должен иметь такой тип, чтобы он вёл себя как список, причём если он не пустой, то его можно будет передать в функцию log, затолкать его первый элемент в кортеж вместе с атомом "yes", и послать другому процессу и т.д.
Фактически я только что рассказал, как будет использоваться этот аргумент в функции. И если мне нужно описать этот тип, то это описание будет фактически повторять то, как он (тип) будет использоваться. То есть дублировать уже то, что написано в самой функции.
Может этот тип ещё где понадобится? Для Эрланга это нехарактерно — каждая функция уникальна, и следовательно аргументы используются уникальным образом. Тип как будто вспыхивает на мгновение при входе в функцию и исчезает после выхода из функции.
Для Явы однако всё по-другому. Какой-нибудь InputStream может быть воткнут повсюду в программе и в каждой точке маскировать разные объекты. Вот теперь я попытаюсь ответить на вопрос, почему статическая типизация работает (хоть и не даёт фантастических результатов).
Вся программа состоит из выражений, где пожалуй особняком стоит вызов методов. Почему?
Работа программы определяется правильным состоянием в каждый момент времени, которое в свою очередь определяется правильным состоянием каждого объекта, поэтому я придаю такое значение именно методам как формирующим чужое состояние. Своим состоянием управлять более-менее научились (в смысле своего класса), а вот чужое может вызвать много всяких эффектов, ньюансы чужого состояния постоянно ускользают из внимания. Так вот, статическая типизация помогает правильно управляться с чужим состоянием.
Подвожу итог.
В одном предложении: вопрос написания ЮТ — это вопрос расстановки приоритетов.
В условиях ограниченного времени приходится выбирать наиболее приоритетные задачи. Поскольку работоспособность кода напрямую зависит от архитектуры, понимания проблемы и эффективного использования окружения, то время выделяется прежде всего на эти задачи. И так как итоговый результат получается удовлетворительный, то юнит-тесты выпадают из рассмотрения. Возможно такие быстрые проекты нужно писать на других языках (ФЯ или тех же динамических) или другим способом (XP, TDD), но без обкатки это большой риск.
Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет, то программа не работает", то у меня закрадывается сомнение — может мы действительно делаем вещи неправильно?
PS: Текст получился великоват, поэтому спасибо за уделённое внимание.
Минусы? Тож спасибо, только маленькая просьба: укажите место с чем именно не согласны.
Lazy Cjow Rhrr wrote: > Здесь программирование происходит в условиях /перманентной/ нехватки > времени. В таких условиях вопрос: "А где юнит-тесты?" звучит как > издевательство. Очевидный ответ на этот вопрос: "А может вам ещё танец > живота на столе станцевать?".
Не знаю, по моему опыту юниттестирования — они как раз помогают писать
быстрее.
> Если такого примера нет, то приходится подбирать > диаметр бубна, цвет ленточек и звук колокольчиков на нём. Процесс этот, > как можно догадаться, недетерминированный.
Не знаю, у меня после многих лет работы выработался рефлекс: "Эта $$%*#$
не работает??? Да я щас возьму дебаггер и отлажу ее нафиг!" (поэтому я
стараюсь использовть только продукты с исходниками).
Ну а то что на настройку и подгонку надо выделять дополнительное время в
проекте — это само собой разумеешеся.
> *1. Писать ЮТ — рутина.* > Кто не согласен, может попробовать выработать творческий подход к коду > наподобие > На мой взгляд единственный элемент творчества здесь — это строковая > константа.
Ага, но такой код пишется на автомате.
> *2. Написание ЮТ отнимает значительное время и требует внимания.* > Этот факт в основном действует как красная тряпка, отвлекая от важных > дел.
А отладка кода занимает еще больше.
> *3. Проверять код взаимодействующий с окружением скорее всего не имеет > смысла.* > (Такая нестрогая формулировка потому, что созданные примеры, > показывающие /как/ надо готовить библиотеки можно назвать > интеграционными тестами, они выполняют роль поэтапных проверок при > разрешении сложных ситуаций).
Угу, поэтому TDD часто неприменим. Тестировать GUI-код с помощью тестов
почти невозможно, а когда возможно — то часто бессмысленно.
> Так вот, чтобы протестировать код, нужно написать правильный конфиг, ну > а дальше вы поняли... Рекурсия, как всегда, божественна.
Вот это как раз достаточно легко побеждается — надо просто помнить, что
нам нужно тестировать не приложение, а код. То есть вместо значений из
конфига ему можно подсунуть захардкоденные строки.
Если код зависит от фреймворка — то либо использовать эмуляцию
интерфейсов фреймворка (google: mock objects), либо курить бамбук.
> Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные > сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет, > то программа не работает", то у меня закрадывается сомнение — может мы > действительно делаем вещи неправильно?
Просто надо помнить: "всякое общее выражение — неверно".
По-моему, использование тестов во многих случаях ничем не вредит
разработке. Например, я пишу интерпретатор и добавляю обработку
инструкции IMPORT_MODULE. Логично, что мне ее надо как-то отладить — а
для этого надо написать тестовую программу. После того, как новая
инструкция интерпретатора работает — нужно просто добавить в тестовую
программу заголовок с эталонным выводом, и тест готов.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Итак.
LCR>Высказывание "Если юнит-тестов нет, то программа не работает" — это догма. И как любая другая догма она является ложной, поскольку не учитывает многообразие реального мира.
Вот с этим я не согласен , поскольку не видел подобного утверждения в перечисленных форумах (вероятно просмотрел?).
Может тебе будет интересно, что я год назад высказал по поводу unit-тестов (в основном для C++): Re[7]: Зачем нужен cppunit?
. Мне кажется, что в основных идеях мы с тобой довольно сильно пересеклись, хотя твое описание проблемы гораздо серьезнее.
LCR>Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет, то программа не работает", то у меня закрадывается сомнение — может мы действительно делаем вещи неправильно?
Имхо, здесь есть два фактора:
* излишний пиетет перед авторитетами. Лучше уж вспомнить поговорку "На бога надейся, а сам не плошай". Это всегда так -- на словах все такие умные и грамотные, что спасу нет. А как посадишь рядом с собой и спросишь, как вот эту хрень работать заставить или как ее лучше реализовать -- так все авторитеты куда-то сразу улетучиваются;
* unit-тест очень ограничен по своему контексту -- как только приходится браться за что-то более сложное, чем конвертация валют или организация двухсвязного циклического списка, так оказывается, что нужно имитировать окружение, в котором тестируемый объект должен работать. Например, у нас с SObjectizer-ом такая ситуация -- невозможно протестировать агента не запустив его в рамках SObjectizer (да еще создать специфические условия). И, на первый взгляд, проще плюнуть на unit-тесты, чем пытаться их применять в таких условиях (существуют решения и для подобных задач, скажем Mock-объекты, но я пока их в реальности не пробовал).
Однако, влияние второго фактора можно снизить (к сожалению, только снизить, а не устранить), если создавать код изначально предназначенный для покрытия его unit-тестами. Например, я сейчас добавляю новую функциональность в C++ную DLL-ку. Причем модифицируются и добавляются классы, которые из этой DLL не экспортируются (т.е. снаружи не видны). Первоначально библиотека была написана так, что ее можно было проверить только на имитационном стенде, путем имитации реальной работы программы. Но сейчас я очень хочу иметь возможность контролировать ее с помощью unit-тестов. Выход в результате нашелся такой -- вынесение части функциональности из DLL в статические библиотеку. И создание unit-тестов, которые линкуются к этим LIB-ам. Т.е. появилась дополнительная сложность -- кроме решения задач самой библиотеки я еще вынужден придумывать, как же ее автоматом протестировать.
Но фокус как раз в том, что эта сложность окупается. Не сразу, но окупается. Например, тот же SObjectizer изначально не имел unit-тестов, только тестовые программы, результат которых нужно было анализировать разработчику. Но по мере переноса SObjectizer на разные платформы и компиляторы проводить такой анализ стало просто нереально. Поэтому практически все тесты пришлось переделать под unit-тесты, чтобы иметь возможность автоматически получать результат проверки.
Так что резюмируя:
* unit-тесты не панацея;
* unit-тесты это всего лишь инструмент с весьма органиченными возможностями;
* unit-тесты обходятся не дешево;
* unit-тесты необходимо применять с самого начала разработки;
* unit-тесты требуют дисциплины;
* unit-тесты окупаются;
Как видишь, есть только один положительный момент
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Вот с этим я не согласен , поскольку не видел подобного утверждения в перечисленных форумах (вероятно просмотрел?). Почему ваш код – отстой
Здравствуйте, GlebZ, Вы писали:
E>>Вот с этим я не согласен , поскольку не видел подобного утверждения в перечисленных форумах (вероятно просмотрел?). GZ>Почему ваш код – отстой
Нет, там по другому, там отстоем обзывают. А работающий и приносящий деньги код вполне можно обозвать отстоем, фигней, гадостью, ламерством, признаками ошибок в ДНК и пр. -- работающий код все это спокойно перенесет
Речь шла о фразе:
"Если юнит-тестов нет, то программа не работает"
Программа вполне может работать без unit-тестов, проверено на практике.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы.
Хотите рассмотреть на примерах ? С удовольствием.
Здравствуйте, minorlogic, Вы писали:
M>Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы.
Это не является юнит-тестом, т.к. требует участия человека, поторый перевел бы приложение в такое состояние чтобы ассерт сработал.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>1. Писать ЮТ — рутина.
По разному. Если у тебя на выходе xml полученный с эталонной базы данных, и ты его должен проверить по нескольким параметрам, то тут уже меньше рутины и больше творчества. По таким тестам и рефакторинг проводится. К тому же у тестов есть дополнительный бонус: он показывает/уточняет разработчику — что же должна делать его функциональность в данном конкретном месте.
На самом деле проблема самих unit-тестов в том, что они тестируют совсем не то что тестирует заказчик..
заказчик тестирует полное приложение, а unit тесты тут как раз лажают..
нужны именно функциональные тесты.. минимум..
и только если всё приложение вдруг перестаёт работать нужно прописывать тесты для его частей
т.е. не снизу вверх по дереву компонентов, а сверху вниз..
Cyberax,
>> Здесь программирование происходит в условиях /перманентной/ нехватки >> времени. C>Не знаю, по моему опыту юниттестирования — они как раз помогают писать быстрее.
В длительной перспективе — охотно верю, даже вижу подтверждение этому собственными глазами. Но когда каждый день на счету — трата времени, ибо есть более приоритетные задачи.
>> Если такого примера нет, то приходится подбирать >> диаметр бубна, цвет ленточек и звук колокольчиков на нём. Процесс этот, >> как можно догадаться, недетерминированный. C>Не знаю, у меня после многих лет работы выработался рефлекс: "Эта $$%*#$ C>не работает??? Да я щас возьму дебаггер и отлажу ее нафиг!" (поэтому я C>стараюсь использовть только продукты с исходниками).
Да, абсолютно согласен, Open Source просто спасение.
C>Ну а то что на настройку и подгонку надо выделять дополнительное время в C>проекте — это само собой разумеешеся.
>> *1. Писать ЮТ — рутина.* >> Кто не согласен, может попробовать выработать творческий подход к коду >> наподобие >> На мой взгляд единственный элемент творчества здесь — это строковая >> константа. C>Ага, но такой код пишется на автомате.
Именно. Синонимом этого высказывания является слово "рутина".
>> *2. Написание ЮТ отнимает значительное время и требует внимания.* >> Этот факт в основном действует как красная тряпка, отвлекая от важных >> дел. C>А отладка кода занимает еще больше.
Упс, обоснуй, пожалуйста: Почему наличие юнит-тестов значительно уменьшает время на отладку?
>> *3. Проверять код взаимодействующий с окружением скорее всего не имеет >> смысла.* >> (Такая нестрогая формулировка потому, что созданные примеры, >> показывающие /как/ надо готовить библиотеки можно назвать >> интеграционными тестами, они выполняют роль поэтапных проверок при >> разрешении сложных ситуаций). C>Угу, поэтому TDD часто неприменим. Тестировать GUI-код с помощью тестов C>почти невозможно, а когда возможно — то часто бессмысленно.
+1.
>> Так вот, чтобы протестировать код, нужно написать правильный конфиг, ну >> а дальше вы поняли... Рекурсия, как всегда, божественна. C>Вот это как раз достаточно легко побеждается — надо просто помнить, что C>нам нужно тестировать не приложение, а код. То есть вместо значений из C>конфига ему можно подсунуть захардкоденные строки.
И умереть при формировании этих захардкоденных строк...
C>Если код зависит от фреймворка — то либо использовать эмуляцию C>интерфейсов фреймворка (google: mock objects), либо курить бамбук.
Мок-объекты делать ручками очевидно? Тогда юнит-тестирование превращается просто в ад: создать мок-объекты к очень даже не тоненьким фреймворками, а потом создать юнит-тесты. В данной ситуации это неприемлемо.
>> Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные >> сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет, >> то программа не работает", то у меня закрадывается сомнение — может мы >> действительно делаем вещи неправильно? C>Просто надо помнить: "всякое общее выражение — неверно".
+1. Я о том же.
C>По-моему, использование тестов во многих случаях ничем не вредит C>разработке. Например, я пишу интерпретатор и добавляю обработку C>инструкции IMPORT_MODULE. Логично, что мне ее надо как-то отладить — а C>для этого надо написать тестовую программу. После того, как новая C>инструкция интерпретатора работает — нужно просто добавить в тестовую C>программу заголовок с эталонным выводом, и тест готов.
Да, в твоём случае ЮТ очень уместно. Однако основной тезис моего высказывания: зачем делать юнит-тесты если можно их не делать?
eao197,
LCR>>Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет, то программа не работает", то у меня закрадывается сомнение — может мы действительно делаем вещи неправильно?
E>Имхо, здесь есть два фактора:
E>* излишний пиетет перед авторитетами... E>* unit-тест очень ограничен по своему контексту...
E>Но фокус как раз в том, что эта сложность окупается. Не сразу, но окупается. Например, тот же SObjectizer изначально не имел unit-тестов, только тестовые программы, результат которых нужно было анализировать разработчику. Но по мере переноса SObjectizer на разные платформы и компиляторы проводить такой анализ стало просто нереально. Поэтому практически все тесты пришлось переделать под unit-тесты, чтобы иметь возможность автоматически получать результат проверки.
Да, я понимаю, что в долгосрочной перспективе ЮТ нужны, и чем дальше от начала, тем нужнее. Я просто описал ситуацию, где они приносят в основном вред (тратят время и действуют на нервы), а польза не так чтобы заметна.
E>Так что резюмируя: E>* unit-тесты не панацея; E>* unit-тесты это всего лишь инструмент с весьма органиченными возможностями; E>* unit-тесты обходятся не дешево; E>* unit-тесты необходимо применять с самого начала разработки; E>* unit-тесты требуют дисциплины; E>* unit-тесты окупаются; E>Как видишь, есть только один положительный момент
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
M>>Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы. L>Это не является юнит-тестом, т.к. требует участия человека, поторый перевел бы приложение в такое состояние чтобы ассерт сработал.
Наверное я скажу глупость , а ваши юнит тесты сами себя запускают ?
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Да, я понимаю, что в долгосрочной перспективе ЮТ нужны, и чем дальше от начала, тем нужнее. Я просто описал ситуацию, где они приносят в основном вред (тратят время и действуют на нервы), а польза не так чтобы заметна.
Ща провокационную вещь скажу, но все таки: если в условиях цейтнота не хватает времени на тестирование приложения (в том числе и на написание unit-тестов), то это является признаком того, что используется не самый подходящий инструмент (не только и не столько язык программирования, сколько набор библиотек/фреймворков).
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, minorlogic, Вы писали:
M>>>Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы. L>>Это не является юнит-тестом, т.к. требует участия человека, поторый перевел бы приложение в такое состояние чтобы ассерт сработал.
M>Наверное я скажу глупость , а ваши юнит тесты сами себя запускают ?
Они не запускают сами себя, но: в юнит-тестах опредлен некоторый набор данных/условий, каждое из которых при запуске проверяется. Т.е. в данном случае программист вручную не должен моделировать все эти ситуации, они один раз написаны и точка. Он просто запустил юнит-тест. А в случае с ассертами, который ты привел, ты каждый раз должен будешь моделировать вручную некоторый набор ситуаций, при которых модуль/программа могут не отработать. Вот это думаю и имелось ввиду
... << RSDN@Home 1.2.0 alpha rev. 655>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
GlebZ wrote: > E>Речь шла о фразе: > > "Если юнит-тестов нет, то программа не работает" > > Утверждение 1: > > Ваш код – отстой, если он не работает > > Утверждение 2: > > Если ваш код не имеет тестов, он – отстой. > > Сокращаем данные утверждения найденные в главе, получаем исходное > сообщение.
vvaizh,
V>На самом деле проблема самих unit-тестов в том, что они тестируют совсем не то что тестирует заказчик.. V>заказчик тестирует полное приложение, а unit тесты тут как раз лажают.. V>нужны именно функциональные тесты.. минимум.. V>и только если всё приложение вдруг перестаёт работать нужно прописывать тесты для его частей V>т.е. не снизу вверх по дереву компонентов, а сверху вниз..
Воот. Функциональные тесты — товарищ копирует себе новоиспечённый дистрибутив, задаёт вопрос "а что эта прога должна делать?" и потом потирая ручки "ща, посмотрим...".
V>что касается рутины описания V>
V>проще сваливать аггрегатные структуры в текстовый файл и сравнивать его рутины будет гораздо меньше
БТВ, мне тоже приходила мысль про сравнение с эталонным выводом, но во-первых, его же тоже нужно формировать руками; во-вторых такая конструкция очень неустойчива по отношению к рефакторингу. Но всё-равно спасибо.
raskin,
R>А, если Б. R>Если В, то А. R>Связь между В и Б?
Да ладно, там рядом есть вполне характерная фраза
Без адекватных тестов (подразумевая – как по количеству, так и по качеству), вы просто не можете иметь уверенность в том, что ваш код работает как нужно.
V>>проще сваливать аггрегатные структуры в текстовый файл и сравнивать его рутины будет гораздо меньше LCR>БТВ, мне тоже приходила мысль про сравнение с эталонным выводом, но во-первых, его же тоже нужно формировать руками; во-вторых такая конструкция очень неустойчива по отношению к рефакторингу. Но всё-равно спасибо.
ну можно по максимуму использовать стандартные сериализаторы в xml
с форматированием..
а для рефакторинга пользоваться специальными средствами типа моего, или как в той ветке WolfHound описал,
т.е. чтобы отличия показывала система конторя версий
LCR> — Да, да, конечно, — сказал им Роман. — Времени у нас мало.
LCR> — Мало? — переспросил я. — Ты ошибаешься. Времени у нас нет вообще!
LCR> (с) Стругацкие,
По моему тут проблема не в юнит тестах как таковых.
Просто в жестоких временных рамках есть потребность родить что-то функционирующее при определенных условиях (например: в солнечную и сухую погоду )
Юнит-тесты в этом случае будут лишь одной из жертв такого подхода.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Cyberax,
C>>Ага, но такой код пишется на автомате. LCR>Именно. Синонимом этого высказывания является слово "рутина".
Рутина, это по пятнадцать раз нарываться на теже грабли, которые могли быть
протестированны автоматом сразу после внесенных изменений.
LCR>Упс, обоснуй, пожалуйста: Почему наличие юнит-тестов значительно уменьшает время на отладку?
Да тот же Гуй, чтоб воспроизвести ситуацию, может быть необходимо раз пятнадцать ткнуть мышкой и только потом попадаеш в дебагер,
находишь косяк, и опять раз пятнадцать мышкой мышкой рррр.
А если код тестировался _с самого начала_, то как правило удается свести ситуацию к полному автомату.
Особый кайф начинается с базами данных, запустил тест, тест наполнил базу чем надо, продебагил код, рооолбэк!
C>>Угу, поэтому TDD часто неприменим. Тестировать GUI-код с помощью тестов C>>почти невозможно, а когда возможно — то часто бессмысленно.
Воот, задача гуевого программиста сделать тестирование GUI бессмысленным, так чтобы большинство косяков
были из разряда, о блин опечатался, или о блин не сделал. Все косяки с моделью отруливаются тестами модели.
C>>По-моему, использование тестов во многих случаях ничем не вредит C>>разработке. Например, я пишу интерпретатор и добавляю обработку C>>инструкции IMPORT_MODULE. Логично, что мне ее надо как-то отладить — а C>>для этого надо написать тестовую программу. После того, как новая C>>инструкция интерпретатора работает — нужно просто добавить в тестовую C>>программу заголовок с эталонным выводом, и тест готов. LCR>Да, в твоём случае ЮТ очень уместно. Однако основной тезис моего высказывания: зачем делать юнит-тесты если можно их не делать?
А что если нет:
1) Если не делать юнит тесты тогда надо писать подробную документацию к коду. ЮТ зачастую могут служить хорошим примером как пользоваться свежесозданными кодом.
2) Необходима замена правилу — нашел баг, написал тест, поправил код. У меня сейчас главная проблема — поменяли немножко код, где гарантия,
что пятилетний опыт отслеживания и правки глюков на самых различных входных данных не пошел насмарку? А внешний мир, он слишком нетипизированный. Проблема в том, что если код писался без тестов, тесты написать очень сложно.
-- Главное про деструктор копирования не забыть --
Здравствуйте, eao197, Вы писали:
E>Речь шла о фразе:
"Если юнит-тестов нет, то программа не работает"
E>Программа вполне может работать без unit-тестов, проверено на практике.
А как только хочется немного расширить и углубить... http://kmmbvnr.livejournal.com/13466.html
-- Главное про деструктор копирования не забыть --
Здравствуйте, minorlogic, Вы писали:
M>Читал ветку по контрактному программированию и юнит тесты , читаю эту .
M>Мне кажется забыт очень важный момент. Почему так преданы забвению старые добрые методы отладки применяемые нашими дедушками ?
А потому, что забыто что вгоняли на вход этих ASSERT'ов наши старые добрые дедушки. А ловить теже глюки в продакшене как-то не хочется
-- Главное про деструктор копирования не забыть --
Здравствуйте, mishaa, Вы писали:
M>Здравствуйте, minorlogic, Вы писали:
M>>Читал ветку по контрактному программированию и юнит тесты , читаю эту .
M>>Мне кажется забыт очень важный момент. Почему так преданы забвению старые добрые методы отладки применяемые нашими дедушками ?
M>А потому, что забыто что вгоняли на вход этих ASSERT'ов наши старые добрые дедушки. А ловить теже глюки в продакшене как-то не хочется
eao197,
LCR>>Да, я понимаю, что в долгосрочной перспективе ЮТ нужны, и чем дальше от начала, тем нужнее. Я просто описал ситуацию, где они приносят в основном вред (тратят время и действуют на нервы), а польза не так чтобы заметна.
E>Ща провокационную вещь скажу, но все таки: если в условиях цейтнота не хватает времени на тестирование приложения (в том числе и на написание unit-тестов), то это является признаком того, что используется не самый подходящий инструмент (не только и не столько язык программирования, сколько набор библиотек/фреймворков).
Вопрос на засыпку: кто и когда будет изучать "подходящий инструмент"? Когда этот "подходящий инструмент" будет обкатываться?
Например, мы используем ant. Антовские скрипты великолепны, когда маленькие, и ужасны, когда большие. Вдруг, мы узнаём, что есть такая великая вещь, как maven. Быстро, в темпе вальса переезжаем на maven? Самоубийство, нужно сначала попробовать. Скачиваем maven, скачиваем какой-нибудь проект, завязанный на maven. Набираем в командной строке
maven
Какого х**? Почему он лезет в inet и качает кучу всего, когда оно уже есть в локальном каталоге. Начинаются раскопки...
Совершенно аналогичная ситуация с гуями, контейнерами (jee, spring, pico, nano, yan), xml-биндингом, ОРМ (Хибернейт в-основном рулит, но вдруг?) и т.п. Преимущества других библиотек на первый взгляд очевидны (возможности круче, комьюнити больше), а начнёшь ковыряться — и тут
Как говорят на востоке: "Самая короткая дорога — та, которую знаешь".
(Или я не понял о каком тестировании и инструменте речь).
Здравствуйте, ekamaloff, Вы писали:
E>Здравствуйте, minorlogic, Вы писали:
M>>>>Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы. L>>>Это не является юнит-тестом, т.к. требует участия человека, поторый перевел бы приложение в такое состояние чтобы ассерт сработал.
M>>Наверное я скажу глупость , а ваши юнит тесты сами себя запускают ?
E>Они не запускают сами себя, но: в юнит-тестах опредлен некоторый набор данных/условий, каждое из которых при запуске проверяется. Т.е. в данном случае программист вручную не должен моделировать все эти ситуации, они один раз написаны и точка. Он просто запустил юнит-тест. А в случае с ассертами, который ты привел, ты каждый раз должен будешь моделировать вручную некоторый набор ситуаций, при которых модуль/программа могут не отработать. Вот это думаю и имелось ввиду
Ну так и асерты не от балды ставятся , а с целью покрыть максимум рабочих ситуаций. И тогда простой запуск приложения в штатном режиме , уже сам по себе юнит тест. А если для него есть еще и набор проверочных сценариев ...
В итоге получается ТОТ же самый юнит тест , но уже ВНЕДРЕННЫЙ в код , со всеми вытекающими преимуществами.
GlebZ,
LCR>>1. Писать ЮТ — рутина. GZ>По разному. Если у тебя на выходе xml полученный с эталонной базы данных, и ты его должен проверить по нескольким параметрам, то тут уже меньше рутины и больше творчества. По таким тестам и рефакторинг проводится. К тому же у тестов есть дополнительный бонус: он показывает/уточняет разработчику — что же должна делать его функциональность в данном конкретном месте.
Тебе не трудно будет привести примерчик, что за параметры и что за xml. Хотя бы с высоты птичьего полёта?
Lazy Cjow Rhrr wrote: > C>Не знаю, по моему опыту юниттестирования — они как раз помогают писать > быстрее. > В /длительной/ перспективе — охотно верю, даже вижу подтверждение этому > собственными глазами. Но когда каждый день на счету — трата времени, ибо > есть более приоритетные задачи.
Это скорее задача менеджмента проекта.
> C>Ага, но такой код пишется на автомате. > Именно. Синонимом этого высказывания является слово "рутина".
Ну отлаживать код иногда тоже надоедает
>> > *2. Написание ЮТ отнимает значительное время и требует внимания.* >> > Этот факт в основном действует как красная тряпка, отвлекая от важных >> > дел. > C>А отладка кода занимает еще больше. > Упс, обоснуй, пожалуйста: Почему наличие юнит-тестов значительно > уменьшает время на отладку?
Большинство багов, на которые тратится много времени, возникают когда
изменение в одном модуле ломают что-то в другом. Без unit-тестов это
обнаружится только когда функциональность другого модуля все-таки вызовут.
Unit-тесты тут замечательно помогают — ты очень точно можешь отловить
момент когда что-то сломалось. Соответственно, ты еще помнишь что только
что изменял и обычно легко можешь найти багу.
Ну и уже написанные unit-тесты при изменении существующего кода
(добавлении оптимизации, например) позволяют проверить большое
количество частных случаев.
По опыту, время на отладку заметно уменьшается. Я даже для эксперимента
решил использовать ViM вместо Студии, так как отладчик стал менее важен.
Проект, кстати, на С++ (это про статическую типизацию).
> C>Вот это как раз достаточно легко побеждается — надо просто помнить, что > C>нам нужно тестировать не приложение, а код. То есть вместо значений из > C>конфига ему можно подсунуть захардкоденные строки. > И умереть при формировании этих захардкоденных строк...
Ну зачем же так, надо просто написать тулзу, которая делает слепок
текущей конфигурации.
> C>Если код зависит от фреймворка — то либо использовать эмуляцию > C>интерфейсов фреймворка (google: mock objects), либо курить бамбук. > Мок-объекты делать ручками очевидно?
Полуруками, то есть полуавтоматом. Есть куча инструментов: http://mockcreator.sourceforge.net/ http://www.mockobjects.com/
и т.п.
> Тогда юнит-тестирование > превращается просто в ад: создать мок-объекты к очень даже не тоненьким > фреймворками, а потом создать юнит-тесты. В данной ситуации это неприемлемо.
Для фреймворков есть еще такой метод — создаешь ситуацию для test-case'а
руками (допустим, сделав некоторые действия в IDE), и все еще во время
работы приложения вызываешь тестовую функцию. С помощью специального
mockcreator'а отслеживается какие данные используются тестовой функцией
и делается их статический слепок.
> Да, в твоём случае ЮТ очень уместно. Однако основной тезис моего > высказывания: зачем делать юнит-тесты если можно их не делать?
Сокращает время отладки
mishaa,
C>>>Ага, но такой код пишется на автомате. LCR>>Именно. Синонимом этого высказывания является слово "рутина". M>Рутина, это по пятнадцать раз нарываться на теже грабли, которые могли быть протестированны автоматом сразу после внесенных изменений.
А зачем пятнадцать раз то? Один, он же единственный раз.
Меняемый код то свеженький, и весь загружен в память. (Тем более я ведь в исходном сообщении говорю про наши (быстрые) проектики, а не про ваш (которому по-моему уже 2 года будет))
LCR>>Упс, обоснуй, пожалуйста: Почему наличие юнит-тестов значительно уменьшает время на отладку? M>Да тот же Гуй, чтоб воспроизвести ситуацию, может быть необходимо раз пятнадцать ткнуть мышкой и только потом попадаеш в дебагер, находишь косяк, и опять раз пятнадцать мышкой мышкой рррр. А если код тестировался _с самого начала_, то как правило удается свести ситуацию к полному автомату.
Только он не может тестироваться с самого начала, потому что тестировать сначала особо нечего, чуть позже — непонятно что тестировать, а когда уже становится понятно, что тестировать, уже дедлайн маячит и не до тестов.
Да, чтобы создать тестовый случай, приходится тыркаться, и это очень печально, но такова жизнь. Частичный выход из этой ситуации я нашёл следующий: просто в самом начале явно захардкодить эмуляцию событий, дабы ускорить наступление вышеназванного тестового случая. Важно просто после окончания отладки пробежаться по всем меткам XXX и закомментировать их.
M>Особый кайф начинается с базами данных, запустил тест, тест наполнил базу чем надо, продебагил код, рооолбэк!
Ужас! GlebZ
утверждает, что можно просто сформировать некую xml, построенную по данным из БД, и на ней посмотреть, что неправильно. И код тестирвоать/отлаживать глядя на эту xml.
C>>>Угу, поэтому TDD часто неприменим. Тестировать GUI-код с помощью тестов C>>>почти невозможно, а когда возможно — то часто бессмысленно. M>Воот, задача гуевого программиста сделать тестирование GUI бессмысленным, так чтобы большинство косяков M>были из разряда, о блин опечатался, или о блин не сделал. Все косяки с моделью отруливаются тестами модели.
C>>>По-моему, использование тестов во многих случаях ничем не вредит C>>>разработке. Например, я пишу интерпретатор и добавляю обработку C>>>инструкции IMPORT_MODULE. Логично, что мне ее надо как-то отладить — а C>>>для этого надо написать тестовую программу. После того, как новая C>>>инструкция интерпретатора работает — нужно просто добавить в тестовую C>>>программу заголовок с эталонным выводом, и тест готов. LCR>>Да, в твоём случае ЮТ очень уместно. Однако основной тезис моего высказывания: зачем делать юнит-тесты если можно их не делать?
M>А что если нет: M>1) Если не делать юнит тесты тогда надо писать подробную документацию к коду. ЮТ зачастую могут служить хорошим примером как пользоваться свежесозданными кодом.
Каменты рулят всегда. При наличии ЮТ или без оных. А посмотреть, как пользоваться свежесозданным кодом можно в точке, где он используется. Зачем тратить время на дублирование этой информации, при том что если код очень мягкий, то этот дубликат устаревает очень быстро?
M>2) Необходима замена правилу — нашел баг, написал тест, поправил код. У меня сейчас главная проблема — поменяли немножко код, где гарантия, что пятилетний опыт отслеживания и правки глюков на самых различных входных данных не пошел насмарку? А внешний мир, он слишком нетипизированный.
Ты прав, и это нисколько не противоречит моим словам — я говорил о быстрых проектах. В таких долгостроях (5 лет — это очень даже внушительно) тесты нужны, я обеими руками за.
M>Проблема в том, что если код писался без тестов, тесты написать очень сложно.
+1 К сожалению, да. Но можно. Если проект начинает напоминать "долгострящийся" вид, то нужно начинать строгать тестовые сюиты.
Здравствуйте, Cyberax, Вы писали:
C>Вот это как раз достаточно легко побеждается — надо просто помнить, что C>нам нужно тестировать не приложение, а код.
Вот эта основная мысль по-моему и упускается из вида Lazy Cjow Rhrr.
Если код не протестирован, то как можно говорить о том, что он работает правильно? Отсюда и рождается болезненное восприятие изменения этого кода, потому как неизвестно как себя поведёт этот код при банальных изменениях в нём, а уж о сложных и говорить нечего, а тесты позволяют видеть как ведёт себя код при изменениях.
Тесты прежде всего нужны, чтобы было психологически легче изменять уже написанный код и удостоверятся, что при этом ничего не сломалось. Автоматический рефакторинг заменяет тесты при нефункциональных изменениях кода (то есть в средах где автоматический рефакторинг отсутствует, уверенность работоспособности кода остаётся только на тестах). При функциональных же изменениях без тестов на работоспособность уже не обойтись.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, minorlogic, Вы писали:
M>>В итоге получается ТОТ же самый юнит тест , но уже ВНЕДРЕННЫЙ в код , со всеми вытекающими преимуществами.
L>Если ты готов каждый раз выполнять функции NUnitGui, то флаг тебе в руки и барабан на шею. А я в это время займусь чем-нить более интересным.
Я не понял вообще о чем речь и что такое NUnitGui, я видимо должен знать что это ?
Здравствуйте, minorlogic, Вы писали:
L>>Если ты готов каждый раз выполнять функции NUnitGui, то флаг тебе в руки и барабан на шею. А я в это время займусь чем-нить более интересным.
M>Я не понял вообще о чем речь и что такое NUnitGui, я видимо должен знать что это ?
NUnitGui — программа, выполняющая твои функции в описанном случае. Congratulations, тебя автоматизировали.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Тебе не трудно будет привести примерчик, что за параметры и что за xml. Хотя бы с высоты птичьего полёта?
Функции работали с эталонной базой данных. На выходе у них был результат в виде xml. Для проверки использовались эталонные xml в которых лежали xpath запросы и эталонные данные в том или ином виде(какие данные опциональные, какие-то должны быть в ответе обязательно и т.д.). И никаких моков.
Здравствуйте, Lloyd, Вы писали:
L>NUnitGui — программа, выполняющая твои функции в описанном случае. Congratulations, тебя автоматизировали.
С Xant(MSBuild) можно обойтись и без оных.
Здравствуйте, minorlogic, Вы писали:
M>Поясните плиз , что имелось ввиду ?
Когда-то я два дня потратил на поиск ошибки в релизе. Оказалось, одна нужная функция выполнялась в рамках ASSERT. После этого поклялся более акуратно относиться к ASSERT и стараться не выполнять функции в оных. ASSERT создает разницу функционирования debug и release версии. Это не есть good.
Andir,
C>>Вот это как раз достаточно легко побеждается — надо просто помнить, что C>>нам нужно тестировать не приложение, а код.
A>Вот эта основная мысль по-моему и упускается из вида Lazy Cjow Rhrr.
A>Если код не протестирован, то как можно говорить о том, что он работает правильно?
Очень даже можно. Как я и говорил, убедиться в том, что он работает, можно наличием другого тестирования. Проверяются все варианты использования, какие нужны, а работа программы при -273'C не требуется. Предлагаешь вместо создания руля и приборной доски устраивать крэш-тесты?
A> Отсюда и рождается болезненное восприятие изменения этого кода, потому как неизвестно как себя поведёт этот код при банальных изменениях в нём, а уж о сложных и говорить нечего, а тесты позволяют видеть как ведёт себя код при изменениях.
Свежий код меняется достаточно легко — мы его только что написали и помним все трещинки.
A>Тесты прежде всего нужны, чтобы было психологически легче изменять уже написанный код и удостоверятся, что при этом ничего не сломалось. Автоматический рефакторинг заменяет тесты при нефункциональных изменениях кода (то есть в средах где автоматический рефакторинг отсутствует, уверенность работоспособности кода остаётся только на тестах). При функциональных же изменениях без тестов на работоспособность уже не обойтись.
Ты прав, и это не противоречит моим словам — в длительной перспективе тесты необходимы. Я же говорил о
Здравствуйте, GlebZ, Вы писали:
L>>NUnitGui — программа, выполняющая твои функции в описанном случае. Congratulations, тебя автоматизировали. GZ>С Xant(MSBuild) можно обойтись и без оных.
Это не принцыпиально. Все равно будет таска, которая эти юнит-тесты прогоняет.
(пули свистели над головой!) LCR>Ты прав, и это не противоречит моим словам — в длительной перспективе тесты необходимы. Я же говорил о
... о срочных проектах.
Здравствуйте, GlebZ, Вы писали:
GZ>Когда-то я два дня потратил на поиск ошибки в релизе. Оказалось, одна нужная функция выполнялась в рамках ASSERT. После этого поклялся более акуратно относиться к ASSERT и стараться не выполнять функции в оных. ASSERT создает разницу функционирования debug и release версии. Это не есть good.
Этой ошибке сто лет в обед. Просто нужно пользоваться VERIFY
... << RSDN@Home 1.2.0 alpha rev. 655>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, ekamaloff, Вы писали:
E>Этой ошибке сто лет в обед. Просто нужно пользоваться VERIFY
Ага. И поставлять всю байду с тестированием клиенту?
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, ekamaloff, Вы писали:
E>>Этой ошибке сто лет в обед. Просто нужно пользоваться VERIFY GZ>Ага. И поставлять всю байду с тестированием клиенту?
Какую байду с тестированием? VERIFY из релиза выкидывается, а вычисление подскобочного выражения остается
... << RSDN@Home 1.2.0 alpha rev. 655>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, minorlogic, Вы писали:
M>>Поясните плиз , что имелось ввиду ? GZ>Когда-то я два дня потратил на поиск ошибки в релизе. Оказалось, одна нужная функция выполнялась в рамках ASSERT. После этого поклялся более акуратно относиться к ASSERT и стараться не выполнять функции в оных. ASSERT создает разницу функционирования debug и release версии. Это не есть good.
Ну можно и не такое написать ... ASSERT то сам не виноват ? правда ?
"ASSERT создает разницу функционирования debug и release версии. Это не есть good" — это и есть самое главное преимущество в ASSERT. В отладочной сборке он проверяет условия , но в релизной не тратит на это ресурсов.
То есть , любой инструмент надо УМЕТЬ использовать
Здравствуйте, minorlogic, Вы писали:
M>В итоге получается ТОТ же самый юнит тест , но уже ВНЕДРЕННЫЙ в код , со всеми вытекающими преимуществами.
Только при том условии, что будет еще человек, который запустит код и пройдет по всем нужным ветвям развится в программе. А если он забудет некую ветвь правильно протыкать или введет не те данные, в некотором месте, то ассерты ничего не выявят просто потому, что до них не дойдет выполнение программы. Еще более важно — сколько времени человек затратит на это самое воспроизведение азных сиуаций.
В случае юнит-тестов нажимается одна(!) кнопка и все тесты побежали на выполнение. При этом можно быть уверенным, что по всем входным данным, заложенные в этих тестах — проверки выполенны.
З.Ы. никто не мешает ставить в код ассеры и инварианты, просто это все же совсем другая вещь, нежели юнит-тесты.
Здравствуйте, vvaizh, Вы писали:
V>На самом деле проблема самих unit-тестов в том, что они тестируют совсем не то что тестирует заказчик.. V>заказчик тестирует полное приложение, а unit тесты тут как раз лажают.. V>нужны именно функциональные тесты.. минимум..
На самом деле у них просто другая область применения. Юнит-тесты — это помощь программисту, для более быстрого обнаружения и локализации ошибок.
А функциональные тесты тоже нужны — дл ятестирования системы в целом, это да.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>GlebZ,
LCR>>>1. Писать ЮТ — рутина. GZ>>По разному. Если у тебя на выходе xml полученный с эталонной базы данных, и ты его должен проверить по нескольким параметрам, то тут уже меньше рутины и больше творчества. По таким тестам и рефакторинг проводится. К тому же у тестов есть дополнительный бонус: он показывает/уточняет разработчику — что же должна делать его функциональность в данном конкретном месте.
LCR>Тебе не трудно будет привести примерчик, что за параметры и что за xml. Хотя бы с высоты птичьего полёта?
необязательно xml
достаточно просто уметь получить результат запроса к базе данных в виде текста
например так:
Cyberax,
>> C>Не знаю, по моему опыту юниттестирования — они как раз помогают писать >> быстрее. >> В /длительной/ перспективе — охотно верю, даже вижу подтверждение этому >> собственными глазами. Но когда каждый день на счету — трата времени, ибо >> есть более приоритетные задачи. C>Это скорее задача менеджмента проекта.
Задача нашего менеджмента — влезть в уже закрывающуюся дверь лифта, который доставит их к заказчику. Я писал об этом в исходном сообщении.
>>> > *2. Написание ЮТ отнимает значительное время и требует внимания.* >>> > Этот факт в основном действует как красная тряпка, отвлекая от важных >>> > дел. >> C>А отладка кода занимает еще больше. >> Упс, обоснуй, пожалуйста: Почему наличие юнит-тестов значительно >> уменьшает время на отладку? C>Большинство багов, на которые тратится много времени, возникают когда C>изменение в одном модуле ломают что-то в другом. Без unit-тестов это C>обнаружится только когда функциональность другого модуля все-таки вызовут.
Её и так вызывают. Явно. Мышкой. Запуск ради этого и делается.
C>Unit-тесты тут замечательно помогают — ты очень точно можешь отловить C>момент когда что-то сломалось. Соответственно, ты еще помнишь что только C>что изменял и обычно легко можешь найти багу.
C>Ну и уже написанные unit-тесты при изменении существующего кода C>(добавлении оптимизации, например) позволяют проверить большое C>количество частных случаев.
C>По опыту, время на отладку заметно уменьшается. Я даже для эксперимента C>решил использовать ViM вместо Студии, так как отладчик стал менее важен. C>Проект, кстати, на С++ (это про статическую типизацию).
Уфф. Мне до сих пор неочевидно, что создание юнит-тестов + отладка для срочных проектов будет занимать меньше времени, чем просто отладка. Либо ты чего-то не договариваешь, либо что-то не так
Как должен выглядеть процесс разработки? TDD? XP?
>> C>Вот это как раз достаточно легко побеждается — надо просто помнить, что >> C>нам нужно тестировать не приложение, а код. То есть вместо значений из >> C>конфига ему можно подсунуть захардкоденные строки. >> И умереть при формировании этих захардкоденных строк... C>Ну зачем же так, надо просто написать тулзу, которая делает слепок C>текущей конфигурации. C>Есть куча инструментов: C>http://mockcreator.sourceforge.net/ C>http://www.mockobjects.com/ C>и т.п. >> Тогда юнит-тестирование >> превращается просто в ад: создать мок-объекты к очень даже не тоненьким >> фреймворками, а потом создать юнит-тесты. В данной ситуации это неприемлемо. C>Для фреймворков есть еще такой метод — создаешь ситуацию для test-case'а C>руками (допустим, сделав некоторые действия в IDE), и все еще во время C>работы приложения вызываешь тестовую функцию. С помощью специального C>mockcreator'а отслеживается какие данные используются тестовой функцией C>и делается их статический слепок.
Ммм. Всё это очень трудоёмко и нужно разбираться с ними. Хотя спасибо за информацию.
Lazy Cjow Rhrr wrote: > Какого х**? Почему он лезет в inet и качает кучу всего, когда оно уже > есть в локальном каталоге. Начинаются раскопки...
Написано же в доке — работает с репозиториями зависимостей Дальше
раскопки сразу должны показать на дефолтный репозиторий ibiblio.
Здравствуйте, fmiracle, Вы писали:
F>Здравствуйте, vvaizh, Вы писали:
V>>На самом деле проблема самих unit-тестов в том, что они тестируют совсем не то что тестирует заказчик.. V>>заказчик тестирует полное приложение, а unit тесты тут как раз лажают.. V>>нужны именно функциональные тесты.. минимум..
F>На самом деле у них просто другая область применения. Юнит-тесты — это помощь программисту, для более быстрого обнаружения и локализации ошибок.
F>А функциональные тесты тоже нужны — дл ятестирования системы в целом, это да.
проблема в том, что нет единого и стандартного средства позволяющего плавно переходить от одного к другому..
а ведь нужно как..
1. заказчик заказал определённый функционал
2. пользователь быстро его реализовал выкатив первую версию и минимальное количество тестов для
неё (чтобы просто показать что всё функционирует как задумано)
3. заказчик начал тестировать глубже, находить что то новое или просто требовать небольшие новые фишки
4. дописываются тесты на эти случаи/рефакторинги, при этом используются функ тесты предыдущих итераций,
при необходимости для вещей которые наиболее часто затрагиваются прописываются свои юнит-тесты, которые должны
в той же среде по идее бегать
это — если времени не хватает, нужна скорость разработки..
Lazy Cjow Rhrr wrote: > A> Отсюда и рождается болезненное восприятие изменения этого кода, > потому как неизвестно как себя поведёт этот код при банальных изменениях > в нём, а уж о сложных и говорить нечего, а тесты позволяют видеть как > ведёт себя код при изменениях. > Свежий код меняется достаточно легко — мы его только что написали и > помним все трещинки.
Как раз большая часть ошибок происходит из-за того, что свежий код
ломает другой код. Юнит-тесты как раз повзоляют это выловить и по
горячим следам тут же исправить.
fmiracle wrote: > З.Ы. никто не мешает ставить в код ассеры и инварианты, просто это все > же совсем другая вещь, нежели юнит-тесты.
Более того, verify и assert'ы замечательно дополняют юнит-тесты, так как
сработавший в unit-test'е assert сразу дает причину и место ошибки.
LCR>Короче, такая недружественная практика по отношению к программистам при этом вполне себя оправдывает: продукт в рекордные сроки поставляются клиентам, клиенты кивают головой увидев что нужно, конкуренты курят бамбук. И только программисты слегка оправившись от пережитого "ужоса" понимают, что "ужос" скоро будет опять (очередная порция хотелок), поэтому надо взять рефакторинг и хотя бы причесать код. Опыт показывает, что код, написанный на большой скорости просто ужасен (низкий уровень обобщения, невнятные соглашения, большая избыточность, сильное сцепление), поэтому рефакторить надо.
А вот как раз когда рефакторить надо ЮТ рулят просто неимоверно.
Ситуация из собственного опыта. 4 человека разрабатывают проект. И тут в один прекрасный момент заказчик вспомниает, что через 1,5 недели у него важнейшая выставка, к которой 10(условно) мегафич должны быть готовы. А по плану те же самые 10 мегафич должны быть готовы не ранее чем через 2 месяца. Попытки воззвать к здравому смыслу заказчика не увенчались успехом. И вот начинается "ужос" . 12-14 часовой рабочий день, код колбасится так, что чуть ли дым из клавиатуры не идет . Путем неимоверных усилий функционал таки готов к сроку. Выставка проходит более менее успешно. Естественно появились новые хотелки. Но надо ж сделать рефакториг... Все в команде в принципе с этим согласны. Но как же его сделать ? Проект за полторы недели расколбасного писания превратился в конструкцию весьма похожую на дом из знаменитой истории "Если бы программисты строили дома". При малейшем изменении приходится пробегать по всем веткам приложения, потому что вылететь может что угодно и где угодно. Попытка рефакторинга после таких авралов очень напоминает хождение по высоко натянутому канату с закрытыми глазами. А сроки сдачи те же. Время идет. Функционала нового не добавляется. Да и результатов от рефакторинга особо не видно. Потому что ехать на машине и шагать по канату с закрытыми глазами с одинаковой скоростью сложно. Следующий майлостоун был просрочен на 2 недели. После этого начали писать юнит тесты. Но это не скзака, поэтому рассказов о том что срзау все заработало и стало перкрасным благодаря юнит тестам не будет. Отнюдь. Были свои приколы когда Mock объекты не совсем корректно реализовывали функционал тех вещей, которые они эмулировали, было потрачено время на то чтобы понять как правильно писать юнит тесты, и где они нужны реально, а где их написание не приносит ощутимых доходов. Тем не менее, после внедрения ЮТ при мысле о рефакторинге на лицах команды нет выражения как при сильной зубной или головной боли. ЮТ не панацея, но в death march проектах, их применение оправдано, и дает реальные плоды.
LCR>Ладно, с условиями разобрались. Теперь перечислим факты о ЮТ, которые играют роль, но о которых не очень охотно говорят.
LCR>1. Писать ЮТ — рутина. LCR>На мой взгляд единственный элемент творчества здесь — это строковая константа.
Такие тесты как и было замечено пишутся практически на автомате. Плюс VS 2005 умеет генерировтаь обертки для юнит тестов. Но при ручном написании таких тестов доволно часто возникает соблазн написать именно такие слова
LCR> Вывод: никто кроме самого программиста нормальные тесты не сделает.
Воистину. Тесты пишет тот же человек, что и код.
LCR>Написание обобщённого кода вызывает ощутимый оверхед, такой, что проще забить на это дело и не парить моск. Для тех, кто сомневается: представьте например, два больших, почти идентичных класса LCR>Как избавиться от дублирования? (Это очень даже реальный пример, два увесистых классика имели всего 43 диффа, дублирование мозолило глаз, но альтернативы? — плодить 43 оператора if, или ещё минимум 3 не самых простеньких класса. Плиз!).
Альтернативы как известно всегда есть . Могу работать, а могу и не работать (с).
Да, бывают такие ситуации. И никуда от них не деться.
LCR>2. Написание ЮТ отнимает значительное время и требует внимания. LCR>Этот факт в основном действует как красная тряпка, отвлекая от важных дел. Отвлекать от важных дел он перестанет только когда оно само (написание ЮТ) будет важным делом.
Достаточно 2-3 раза пережить такие этапы как вышеописанный, и наступает понимание что написание ЮТ все-таки важное дело. Может менее важное чем архитектура, но тем не менее важное.
LCR> Тремя словами это будет так: "worse is better".
Адепты TDD утверждают, что разработка идеть в 3 этапа red, green, refactor.
на красном, мы имеем нес рабатывающий тест, на зеленом мы имеем срабатывающий тест, а на рефакторе мы убираем из кода все лишнее. Итого имеем Simplicity И (относительную)Correctness. Принцип worse is better не нарушается
LCR> Хотя очевидно, что это соотношение существует (на мой взгляд процент должен зависеть от типа проекта; чем проект дольше — тем меньше процент, а абсолютная величина больше), и доля тестов весьма ощутима.
+1 Абсолютно согласен
LCR>Плюс необходимость переключать внимание с ЮТ на код и обратно — это разбрасывать шары, а потом их снова скрупулёзно собирать... (неплохая аналогия тов. Спольски). Как минимум — некомфортно. Фактически — расход заметного времени именно на переключение (общеизвестная статистика — вхождение "в поток" съедает 15 минут, умножаем это время на количество прерываний=переключений...).
За всех говорить не буду, но у меня написание класса и юнит тестов находится в одном "потоке". Это не отвлекает, а наоборот, ты предстваляешь КАК будет использоваться то что ты пишешь, и когда тесты написаны, ты знаешь что в большинстве случаев твой код будет работать правильно. А это как минимум приятно. А вот когда вылетает непонятный иксепшен, из-за банального обращения к элементу массива с нумером -1, то это может очень здорово выбить из потока. Повторюсь, речь идет обо мне
LCR>3. Проверять код взаимодействующий с окружением скорее всего не имеет смысла.Такой код часто имеет следующую особенность: он работает только при грамотной конфигурации, наличия нужных джарок в нужных директориях, правильных переменных окружения и т.п. Примеров куча: деплоймент дескрипторы, plugin.xml, web.xml, struts-config.xml, yan.xml и так далее. Часто ошибки именно в неправильной конфигурации.
LCR>Так вот, чтобы протестировать код, нужно написать правильный конфиг, ну а дальше вы поняли... Рекурсия, как всегда, божественна.
В таких случаях используются Mock объекты. Что-то типа "Если все поднимется правильно, то на вызов метода X с параметрами Y окружение должно ответить Z". Но иногда оказывается что реально окружение отвечает AAAA. Тогда возникают проблемы
LCR>В данном случае уже работает выбор худшего из двух зол. Что хуже: ошибка в архитектуре или ошибка в работе метода? Я думаю, что как правило первое хуже.
+1 ЮТ не значить "забить на архитектуру".
LCR>Вдобавок, если юнит-тесты будут, то не будет (или будет в недостаточном количестве) чего-то другого. Как всегда, бесплатный сыр соблазнительно качается на пружинке...
Не будет длительной отладки ? (шутка). На самом деле ты прав. Во всем важен баланс. Способсвует ли отсуствие или наличие ЮТ соблюдению баланса каждый отвечает сам. Ситуации они разные бывают.
LCR>5. Статическая типизация в сочетании с IDE работает удовлетворительно и без тестов.
+1 Но статическая типизация в сочетании с ИДЕ и с юнит тестами работает лучше чем удовлетворительно.
LCR>В одном предложении: вопрос написания ЮТ — это вопрос расстановки приоритетов.
+1
LCR> И так как итоговый результат получается удовлетворительный, то юнит-тесты выпадают из рассмотрения.
ЕСЛИ итоговый результат получается удовлетворительный.
LCR>Возможно такие быстрые проекты нужно писать на других языках (ФЯ или тех же динамических) или другим способом (XP, TDD), но без обкатки это большой риск.
+1
LCR>Чем в данных условиях могут помочь юнит-тесты?
Лично мне очень помогают при рефакторинге. Который неизбежен.
LCR> умные сволочи вроде Эккеля, Фаулера и Бека что "если юнит-тестов нет, то программа не работает",
Скорее всего перегибают палкую для сферической программы в вакууме это скорее всего справедливо.
Итог.
Я виже пользу в юнит тестах исключительно когда нужен рефакторинг. Это помогает сразу же увидеть сломал ты что-то или нет. Особенно это полезно когда в команду приходит новый человек.
Cyberax,
>> Какого х**? Почему он лезет в inet и качает кучу всего, когда оно уже >> есть в локальном каталоге. Начинаются раскопки... C>Написано же в доке — работает с репозиториями зависимостей Дальше C>раскопки сразу должны показать на дефолтный репозиторий ibiblio.
Воот. Я должен буду заглянуть в доку и т.п.
В данном случае может быть всё просто и ноги найдутся через 5 минут. Но можешь ли ты утверждать это для любой библиотеки? Для любой ошибки или любого затруднения? Можешь ли ты утверждать, что переезд с любой библиотеки на другую аналогичную произойдёт легко и безболезненно?
Мы, наученные горьким опытом, стараемся держаться в русле и использовать пользующиеся вниманием и проверенные фреймворки/библиотеки. Много шагов в сторону означает увеличение риска. В частности, Spring выглядит многообещающе, и вроде развивается давно, но мы не используем его. Никто ещё не нашёл возможности и желания попробовать его "на зубок" в фоновом режиме...
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Вопрос на засыпку: кто и когда будет изучать "подходящий инструмент"? Когда этот "подходящий инструмент" будет обкатываться?
А кабы знать!
Это вообще вопрос, на который я пока не слышал вразумительного ответа: "Как изучать что-нибудь новое, когда работой завален по горло?"
Я знаю только один способ: изыскивать время (см. например Сделай это сейчас
) и терпеть. Еще хорошо, когда в команде есть подвинутый на изучении чего-нибудь нового человек (мне как-то повезло в с таким работать). Можно еще вспомнить Брукса с его организацией работы, когда в команде есть отвечающий за инструменты программист.
LCR>Как говорят на востоке: "Самая короткая дорога — та, которую знаешь".
А лучше всего знаешь ту дорогу, которую сам и проложил, поэтому велосипеды рулят!
LCR>(Или я не понял о каком тестировании и инструменте речь).
Здесь можно провести аналогию с языками высокого или низкого уровня. Для того, чтобы открыть файл, прочитать его построчно и выбрать что-то подходящее, на разных языках придется писать разный объем кода. На ассемблере очень много. На C++ гораздо поменьше. На Ruby еще меньше. А если есть возможность запустить grep, то вообще одну строку. Соответственно время решения этой задачи в зависимости от имеющегося в наличии инструмента будет отличаться на порядки.
Если в условиях цейтнота выясняется, что писать приходится слишком много, то очень возможно, что используемый инструмент слишком низкоуровневый для конкретной задачи. Имхо, такие вещи происходят сплошь и рядом, когда берется какой-нибудь универсальный инструмент, а затем на нем в лоб пытаются решать свою проблему. Хотя, очень возможно, задача решилось бы гораздо быстрее, если бы над универсальным инструментом была создана узкозаточенная надстройка. И именно на ее основе создавался бы прикладной код.
Опять буду не скромным и приведу примеры из собственного опыта. Года четыре назад, когда мы только начинали работать с SMPP-транспортом нам приходилось время от времени в очень сжатые сроки обеспечивать поддержку различных SMS-акций (голосования, викторины), да и различные демонстрации наших продуктов к какому-нибудь приезду высоких гостей-заказчиков так же. Имея голую реализацию SMPP-протокола поверх голого же TCP/IP делать это было не очень просто, поскольку кроме прикладной логики нужно было заниматься как деталями TCP/IP взаимодействия, так и деталями SMPP-протокола (в частности, отслеживать времена отсутствия активности и обмениваться периодическими пингами). Ситуация кардинально изменилась, когда над поддержкой SMPP-протокола был выстроен дополнительный логический слой, предоставляющий совсем другую функциональность. Прикладную логику стало возможно программировать с использованием высокоуровневых понятий receive/send, не заботясь о том, во что это выливается в SMPP и в TCP/IP. При этом, однако, была потеряна некоторая степень гибкости в управлении низкоуровневыми деталями протокола, но зато существенно возрасла скорость разработки прикладных решений.
Еще один пример. Я занимаюсь разработкой распределенных приложений на SObjectizer, в которых отдельные модули могут располагаться как в рамках одного процесса, так и в разных процессах. Если модули разносятся по разным процессам, то приходится эти процессы соединять между собой TCP/IP соединениями. При использовании голого SOP в SObjectizer это не представляет проблемы, однако является довольно трудоемкой. В частности, приходится решать две задачи: контроль каналов, через которые должен идти peer-to-peer обмен сообщениями между модулями (т.е. при разрыве и переустановлении TCP/IP соединения имена каналов меняются и их нужно запоминать) и организация этих каналов в процессе при старте. Первая задача разрешилась путем добавления специальной подсистемы над SOP (называемой message box api, чем-то напоминающем message oriented middleware) благодоря которой модулям больше не требуется знать про коммуникационные каналы вообще. Вторая разрешилась посредством создания специальной библиотеки, которая подключается к процессу и берет из конфигурационного файла список нужных подключений и создает для них нужное количество коммуникационных каналов с нужными параметрами. А приложения при таком подходе строятся из DLL-ек как из конструктора (хотя ты подобные вещи знаешь по EJB контейнерам).
Когда приложение собирается из DLL-ек как из конструктора возникает проблема правильного конфигурирования, ведь тогда сложность перемещается в правильность конфигурационных файлов (об этом ты так же говорил). И, если править эти файлы ручками, то можно потратить много времени на устранение последствий глупых ошибок. Но здесь над конфигами можно сделать еще одну собственную прослойку: генератор конфигурационных файлов заточенный под конкретный тип приложения. Например, Ruby-новый DSL, который знает, как преобразовать описания в набор конфигов.
В общем, есть очень тонкий момент, в который можно понять, что обычный способ использования какого-то инструмента оказывается слишком дорогостоящим. В этот момент можно что-то сделать (например, какой-то собственный велосипедик) чтобы упростить использование инструмента для какого-то типа задач. (Существует мнение, что RubyOnRails как раз стал популярным из-за того, что он как раз и является велосипедом для очень ограниченного класса Web-приложений, но зато очень удобным).
Вот как-то так.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Lazy Cjow Rhrr wrote: > C>Это скорее задача менеджмента проекта. > Задача нашего менеджмента — влезть в уже закрывающуюся дверь лифта, > который доставит их к заказчику. Я писал об этом в исходном сообщении.
Даже в это ситуации трезвый подход и распланированное написание тестов
могут сократить время.
> C>Большинство багов, на которые тратится много времени, возникают когда > C>изменение в одном модуле ломают что-то в другом. Без unit-тестов это > C>обнаружится только когда функциональность другого модуля все-таки вызовут. > Её и так вызывают. Явно. Мышкой. Запуск ради этого и делается.
Э, нет.
К примеру, реальная ситуация из все того же проекта: я добавил функцию
IMPORT_MODULE и сделал так, что создание корневого модуля сделано как
импорт пустого модуля. Проверил, это нормально работает.
Запустил тесты — и сразу увидел ошибку. В stacktrace появилось новое звено:
somefile.jam:17 in module ('_ROOT_') scope
somefile.jam:17 in module ('_ROOT_') scope
another.jam:223 in module ('test') scope
...
Ошибка возникла из-за того, что раньше корневой модуль при выводе
stacktrace'а обрабатывался специальным образом.
Без тестов ты эту ошибку можешь заметить намного позже и ее отладка и
исправление может занять больше времени.
> C>По опыту, время на отладку заметно уменьшается. Я даже для эксперимента > C>решил использовать ViM вместо Студии, так как отладчик стал менее важен. > C>Проект, кстати, на С++ (это про статическую типизацию). > Уфф. Мне до сих пор неочевидно, что /создание юнит-тестов + отладка/ для > срочных проектов будет занимать меньше времени, чем /просто отладка/.
Если срочный проект поддается тестированию (не всегда так бывает), то
вполне возможно. В моей практике тесты значительно сокращают время отладки.
> Как должен выглядеть процесс разработки? TDD? XP?
Да хоть RUP. Можно просто рассматривать тесты как один из рабочих
инструментов.
> C>Для фреймворков есть еще такой метод — создаешь ситуацию для test-case'а > C>руками (допустим, сделав некоторые действия в IDE), и все еще во время > C>работы приложения вызываешь тестовую функцию. С помощью специального > C>mockcreator'а отслеживается какие данные используются тестовой функцией > C>и делается их статический слепок. > Ммм. Всё это очень трудоёмко и нужно разбираться с ними. Хотя спасибо за > информацию.
Угу, некоторые mockobject'овые тулзы так и работают.
Здравствуйте, minorlogic, Вы писали:
M>Ну можно и не такое написать ... ASSERT то сам не виноват ? правда ?
А тож.
M>"ASSERT создает разницу функционирования debug и release версии. Это не есть good" — это и есть самое главное преимущество в ASSERT. В отладочной сборке он проверяет условия , но в релизной не тратит на это ресурсов.
Проверяет условия — это конечно хорошо. Но это не юнит тестирование, поскольку в юнит тестировании:
1. Проверяется корректность результатов функции при определенных входных параметрах. И проверяет он явно, показывая что данная функция, с такими параметрами не может работать, а вот с такими на ура.
2. Все проверки вынесены за пределы релизного функционала, и никак не влияют на функционирования самой функции. Нужно захотеть, чтобы перевести систему в состояние, неравнозначное исходному. В случае ASSERT такое возможно неявно.
3. В случае ассерт — мы можем тестировать только те пути, что выполняет тестер. А тестеры обычно не выполняют не все пути исполнения. Хорошо если они хотя бы выполнят функциональные тесты согласно требованиям. Иногда и даже этого не делают. Либо делают до того, как в проект были внесены ошибки.
M>То есть , любой инструмент надо УМЕТЬ использовать
Но это не есть unit тестирование. Максимум что я использую в ассертах — проверка простых переменных в особых случаях.
Здравствуйте, ekamaloff, Вы писали:
E>Какую байду с тестированием? VERIFY из релиза выкидывается, а вычисление подскобочного выражения остается
К тебе приходит результат функции в виде структуры с 3 полями. Ты их хочешь проверить. Ты будешь поднимать VERIFY?
GlebZ wrote: > E>Какую байду с тестированием? VERIFY из релиза выкидывается, а > вычисление подскобочного выражения остается > К тебе приходит результат функции в виде структуры с 3 полями. Ты их > хочешь проверить. Ты будешь поднимать VERIFY?
Надо быть проще
Здравствуйте, GlebZ, Вы писали:
E>>Какую байду с тестированием? VERIFY из релиза выкидывается, а вычисление подскобочного выражения остается GZ>К тебе приходит результат функции в виде структуры с 3 полями. Ты их хочешь проверить. Ты будешь поднимать VERIFY?
Тебе не кажется, что ты уводишь разговор в сторону? Ты привел пример неудачного использования ASSERT, тогда, когда нужно было использовать VERIFY, под видом того, что ASSERT — зло. Я обратил твое внимание на это.
Теперь приводишь непонятный пример со структурой, которая никакого отношения к предыдущему разговору не имеет.
Проверять или не проверять поля этой структуры и где их проверять, если их надо проверять — зависит от задачи. Если невалидные значения допускаются логикой программы, то вариантов может быть много — от комбинаций ASSERT-ов и выброса исключений до корректирования полей этой структуры. Если невалидные значения по логике недопустимы, то ASSERT (при чем тут спршивается VERIFY и где я говорил о том что буду использовать VERIFY ):
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
A>>Если код не протестирован, то как можно говорить о том, что он работает правильно? LCR>Очень даже можно. Как я и говорил, убедиться в том, что он работает, можно наличием другого тестирования. Проверяются все варианты использования, какие нужны, а работа программы при -273'C не требуется. Предлагаешь вместо создания руля и приборной доски устраивать крэш-тесты?
Мне не совсем понятно, как, в условиях недостатка времени, можно надеятся, что человек протестирует быстрее чем компьютер?
1. Когда я писал в VS 6.0 (на C++, понятно) я попытался сделать ЮТ: результат был поразительным: мой код был настолько отстойным, что отстойней просто некуда. Иногда создавалось такое впечатление, что я просто забыл, что и как хотел написать в коде. ЮТ просто выбили меня из задачи. После ещё нескольких попыток я понял, что ЮТ не для меня.
2. ЮТ как средство первичного тестирования неадекватно: они практически неспособны найти настоящие ошибки и часто выдают ложные. Для того, что бы нормально что-то проверить нужно извращаться. Следовательно, первичное тестирование должен делать человек-оператор.
3. Лично я (не призываю последовать за мной) всегда пишу программу так, что могу проверить все написанные мной элементы вручную, даже если работа над программой ещё далека от завершения.
4. Все мои программы содержат проверки на корректность полученного результата вычислений, даже если это заметно снижает производительность. Эти проверки нетривиальны (т.е. это не object.length != 0).
5. Как средство тестирования против разрушения существующего кода изменениями ЮТ являются адекватным средством автоматизации, но не оптимальным
Зачастую, проверить правильность исполнения кода может только человек. По крайней мере, надёжно проверить правильность. Фактически это означает, что ЮТ должны формироваться как запись некоторых действий человека-оператора с проверкой результата на соответствие сохранённому результату.
Проще говоря, это означает, что ЮТ должны быть вовсе не Ю, а КТ (комплексными тестами), которые формируются автоматически наподобие макросов в Excel, например. КТ должен хранить действия человека-оператора и результаты вычислений программы (естественно, только значимые части результатов), возможно, файлы конфигураций, save’ы и т.п.
Такие тесты могут формироваться, в том числе, и при нахождении ошибок оператором, не связанным напрямую с разработчиком (т.е. система формирования тестов может быть встроена в программу, а отчёт об ошибке в программе посылаться в виде соотв. неполного КТ). Что позволит в дальнейшем заранее предсказывать реакцию новой версии программы на действия этого пользователя.
Т.о. ЮТ не есть хорошо. Есть хорошо комплексное автоматизированное тестирование вариантов использования.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, Lazy Cjow Rhrr, Вы писали:
A>>>Если код не протестирован, то как можно говорить о том, что он работает правильно? LCR>>Очень даже можно. Как я и говорил, убедиться в том, что он работает, можно наличием другого тестирования. Проверяются все варианты использования, какие нужны, а работа программы при -273'C не требуется. Предлагаешь вместо создания руля и приборной доски устраивать крэш-тесты?
ANS>Мне не совсем понятно, как, в условиях недостатка времени, можно надеятся, что человек протестирует быстрее чем компьютер?
Лекго и просто: тестировщиков побольше нанять, они стоят дешевле чем программист, который сделает хороший ЮТ
Здравствуйте, GlebZ, Вы писали:
LCR>>Тебе не трудно будет привести примерчик, что за параметры и что за xml. Хотя бы с высоты птичьего полёта? GZ>Функции работали с эталонной базой данных. На выходе у них был результат в виде xml. Для проверки использовались эталонные xml в которых лежали xpath запросы и эталонные данные в том или ином виде(какие данные опциональные, какие-то должны быть в ответе обязательно и т.д.). И никаких моков.
Как то всё сложно. Вот с PostgresSQL идёт набор регресных тестов — там данные в текстовых файлах. Сравнивает один к одному результаты запросов с эталоном. Работает — как из пушки.
FDSC wrote: > ANS>Мне не совсем понятно, как, в условиях недостатка времени, можно > надеятся, что человек протестирует быстрее чем компьютер? > Лекго и просто: тестировщиков побольше нанять, они стоят дешевле чем > программист, который сделает хороший ЮТ
Если это GUI-приложение, то еще можно. А если приложение — это компилятор?
Здравствуйте, GlebZ, Вы писали:
GZ>3. В случае ассерт — мы можем тестировать только те пути, что выполняет тестер. А тестеры обычно не выполняют не все пути исполнения. Хорошо если они хотя бы выполнят функциональные тесты согласно требованиям. Иногда и даже этого не делают. Либо делают до того, как в проект были внесены ошибки.
Нужно снимать на камеру тестера и смотреть, как он работает
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, FDSC, Вы писали:
FDS>>Т.о. ЮТ не есть хорошо. Есть хорошо комплексное автоматизированное тестирование вариантов использования.
L>Море воды и ни капли конструктива. Покажи пример такой системы о которой ты говоришь.
Море конструктива. Я предлагают это делать и я кое-что из этого делаю. Если бы система уже была, я бы дал ссылку и не очем было бы говорить в философии.
Если вы считаете, что я написал воду, критикуйте эту воду. Так и пишите: это тривиально, то недоказано и т.п.
Здравствуйте, FDSC, Вы писали:
FDS>Море конструктива. Я предлагают это делать и я кое-что из этого делаю. Если бы система уже была, я бы дал ссылку и не очем было бы говорить в философии. FDS>Если вы считаете, что я написал воду, критикуйте эту воду. Так и пишите: это тривиально, то недоказано и т.п.
Это прекрасный и безупречный сферический конь в вакууме. У тех, кто тестирует код стоит задача тестирования кода, а не написания инструмента для тестирования. Кажется это обсуждают в этой теме.
Здравствуйте, ekamaloff, Вы писали:
E>Тебе не кажется, что ты уводишь разговор в сторону? Ты привел пример неудачного использования ASSERT, тогда, когда нужно было использовать VERIFY, под видом того, что ASSERT — зло. Я обратил твое внимание на это.
Нет. Не должно было там использоваться VERIFY. Это совершенно разные функции. О чем я тебе и сообщил.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, FDSC, Вы писали:
FDS>>Море конструктива. Я предлагают это делать и я кое-что из этого делаю. Если бы система уже была, я бы дал ссылку и не очем было бы говорить в философии. FDS>>Если вы считаете, что я написал воду, критикуйте эту воду. Так и пишите: это тривиально, то недоказано и т.п.
L>Это прекрасный и безупречный сферический конь в вакууме. У тех, кто тестирует код стоит задача тестирования кода, а не написания инструмента для тестирования. Кажется это обсуждают в этой теме.
А я не говорю, что они должны писать инструмент.Это то же самое, что сказать, что программист C++ должен написать компилятор C++ перед программированием. Мало того, я даже не говорю, что кто-то этот инструмент должен создавать. Я обхожусь без него, просто всё было сказано так, как по моему это было бы в идеале. И водяного тут не больше, чем у автора темы: и там, и там вс построено на личном опыте. Мало того, я предлагаю выход, а он просто говорит: вот ЮТ это хорошо, но они ничем помочь не могут.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>... о срочных проектах.
Тута есть еще одна штука. Если брать классические процессы, и это не система сделанная на коленке, то обычно действует правило 40-20-40, где 40 процентов времени занимет постановка, 20 программирование, и 40 процентов тестирование и отладка. Юнит-тесты могут сократить последнюю цифру.
Здравствуйте, Cyberax, Вы писали:
C>FDSC wrote: >> ANS>Мне не совсем понятно, как, в условиях недостатка времени, можно >> надеятся, что человек протестирует быстрее чем компьютер? >> Лекго и просто: тестировщиков побольше нанять, они стоят дешевле чем >> программист, который сделает хороший ЮТ C>Если это GUI-приложение, то еще можно. А если приложение — это компилятор?
Хм. И как его протестировать Unit тестами? Не смешите меня...
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, FDSC, Вы писали:
FDS>>Лекго и просто: тестировщиков побольше нанять, они стоят дешевле чем программист, который сделает хороший ЮТ
ANS>Время? Скорость коммуникации между тестером и программистом на несколько порядков меньше скорости коммуникации программиста с собственным кодом.
Смотря где. Тестерам не нужно коммуникаций: если есть ошибка идёт к программисту и говорит обо всём. Они должны работать бок о бок.
Всё равно ЮТ ничего не выявят на первых порах, именно когда сроки жмут.
Здравствуйте, FDSC, Вы писали:
FDS>Смотря где. Тестерам не нужно коммуникаций: если есть ошибка идёт к программисту и говорит обо всём. Они должны работать бок о бок.
Шутку понял. Смешно.
FDS>Всё равно ЮТ ничего не выявят на первых порах, именно когда сроки жмут.
А в конце сроки перестают жать? Привычка появляется?
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Как то всё сложно. Вот с PostgresSQL идёт набор регресных тестов — там данные в текстовых файлах. Сравнивает один к одному результаты запросов с эталоном. Работает — как из пушки.
ANS>Или ты о чем то другом?
Почти. Тут тестируются не запросы БД как таковые, а функции. А полученный результат из БД может ими значительно трансформироваться на разных слоях системы.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
FDS>>Всё равно ЮТ ничего не выявят на первых порах, именно когда сроки жмут.
ANS>А в конце сроки перестают жать? Привычка появляется?
Нет, они разнашиваются. Я имею ввиду, что ЮТ не может найти ошибку, он может только показать, что ты испортил уже правильную оттестированную другими методами программу.
Ладно, вообще смысл есть, в том что я сказал, но в общем я не совсем прав
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, minorlogic, Вы писали:
M>>Ну можно и не такое написать ... ASSERT то сам не виноват ? правда ? GZ>А тож.
M>>"ASSERT создает разницу функционирования debug и release версии. Это не есть good" — это и есть самое главное преимущество в ASSERT. В отладочной сборке он проверяет условия , но в релизной не тратит на это ресурсов. GZ>Проверяет условия — это конечно хорошо. Но это не юнит тестирование, поскольку в юнит тестировании:
А я не утверждаю что это заменяет юнит тестирование , я говорю что во многих случаях это очень сильно спасает , иногда даже сводит необходимость юнит тестирования на нет.
Просто это намного эфективнее подавляющего большинства тестов. Тесты ведь тоже не могут покрыть ВСЕ разнообразие входных данных при реальной работе . А асертные проверки проверяют ВСЕ данные с которыми работает пользователь.
GZ>1. Проверяется корректность результатов функции при определенных входных параметрах. И проверяет он явно, показывая что данная функция, с такими параметрами не может работать, а вот с такими на ура.
Ну собственно в БОЛЬШИНСТВЕ случаев штатный запуск программы это именно то что и требуется проверить.
GZ>2. Все проверки вынесены за пределы релизного функционала, и никак не влияют на функционирования самой функции. Нужно захотеть, чтобы перевести систему в состояние, неравнозначное исходному. В случае ASSERT такое возможно неявно.
Вот этот пункт я простоне понял , подробнее плиз.
GZ>3. В случае ассерт — мы можем тестировать только те пути, что выполняет тестер. А тестеры обычно не выполняют не все пути исполнения. Хорошо если они хотя бы выполнят функциональные тесты согласно требованиям. Иногда и даже этого не делают. Либо делают до того, как в проект были внесены ошибки.
Для этого также есть и бета тестеры , но это отдельный разговор , я уже говорил , что юнит тестов эти проверки не заменяют. Но если есть возможность проверить нечно в рантайме — это необходимо делать там , а не в юнит тесте.
M>>То есть , любой инструмент надо УМЕТЬ использовать GZ>Но это не есть unit тестирование. Максимум что я использую в ассертах — проверка простых переменных в особых случаях.
Вот и зря , классический пример , который я привожу — сериализация и десиаризация . Серилизовал — тут же десиреализуй и сравни реальные объекты. Если пользуешь связаный список , обязательно после операция изменяющих список — провалидейть целосность списка.
Если обрабатываешь енум , проверь что ты обрабатываешь ВСЕ возможные значения, если вставляешь ключ в мепку , убедись что он уникален , и т.п.
Т.е. покрыть это все юнит тестами просто НЕРЕАЛЬНО !!!
Здравствуйте, minorlogic, Вы писали:
M>Просто это намного эфективнее подавляющего большинства тестов. Тесты ведь тоже не могут покрыть ВСЕ разнообразие входных данных при реальной работе . А асертные проверки проверяют ВСЕ данные с которыми работает пользовател
Тестер, не пользователь.
И тестер тоже запросто можешь не покрыть все варианты, с которыми будет потом работать пользователь... И это еще если нормальный отдельный тестер.. А если это программист, который в это же время код фигачит — то вообще труба — глаз засаливается... Не говоря уже о том, что ему просто некогда проводить аккуратное и вдумчивое тестирование в процессе изменения кода...
Здравствуйте, FDSC, Вы писали:
FDS>1. Когда я писал в VS 6.0 (на C++, понятно) я попытался сделать ЮТ: результат был поразительным: мой код был настолько отстойным, что отстойней просто некуда. Иногда создавалось такое впечатление, что я просто забыл, что и как хотел написать в коде. ЮТ просто выбили меня из задачи. После ещё нескольких попыток я понял, что ЮТ не для меня.
У меня тоже такое было. И тесты фиговые получались, и код корежило ужасно, чтобы обеспечить доступ тестам к нужной (как мне тогда казалось) информации. Забросил я их. Потом, набравшись опыта вообще и прочитав разных книг, включая книги про ЮТ — решил, что можно опять попробовать, ибо достало править глупые ошибки, для обнаружения которых надо забить длинную экранную форму в программе... И вот сейчас они уже начинают облегчать мне работу.
Я, правда, перестал думать, что ЮТ обеспечат меня надежной и безошибочной программой, а стал относиться к ним как к средствую повышения скорости отладки. Точнее — скорости обнаружения и локализации ошибок. А так же — средство поразмыслить над тем, что же я вообще пишу — ЮТ я пишу одновременно с кодом (то сперва код, потом тесты, то наоборот — по ситуации, но примерно в одно время) — это не выбивает меня из потока, наоборот позволяет рассмотреть ситуацию с разных сторон и подумать о возможных слабых местах, а потом сразу посмотреть — нормально оно заработало оно или нет. Часто код и тесты вообще пишутся параллельно — тут придумал новый тест — и даже без запуска понял, что эта ситуация в коде не предусмотрена — пошел дописал, заодно придумал еще тест.
Отличный анализ!
Добавлю свои 5 копеек в качестве истории последних пары дней.
Недавно нашли проблему. Серьезную. Установили возраст — около полугода.
Как раз в то время добавляли новые фичи. Времени, как обычно, в притык, так как заказчик только сегодня понял, что эта функциональность нужна ему уже вчера, и, как жить без нее дальше, он просто представить себе не может. Что ж, надо, так надо. Сели, в сжатые до размеров Белаза ползущего по краю дырочки ;)
сроки все сделали. Однако в процессе один из наших хлопцев (не исключаю, что это мог быть и я) меняет в теле метода одного из ключевых классов строчку с
return _tables[name];
на
return _tables[name].Clone();
В итоге все продолжает работать на ура.... А через пол года выясняется, что работает все, кроме одного.
К чему я все это. Да к тому, что ЮТ были: на этот метод с несколько десятков! Но ни один не проверял запрет клонирования таблицы. Все значения этой таблицы тестили. Более того, вариант с клоном был правильным — нельзя было позволять править значения в начальной таблице, и кто-то это заметил и, умничка, поправил. Ни один тест не покраснел. Да и признаться, вряд ли кому в голову в момент написания тестов пришло бы предвидиние такой ситуации, ведь, как казалось, тут и ребенку все очевидно — таблицу менять нельзя!
Теперь такой тест есть
А не было бы на этот метод ЮТ совсем, может (мечтать ведь не вредно ) и не родился бы такой баг (родились бы с 10ок других ). На них [тесты] ведь в какой-то мере надеешься.
Какой из этого всего вывод сделал я? Когда сроки сжаты — в лес рефакторинг! Надо тебе клон — создай новый метод:
и забудь про старый, а рефакторить потом как-нибудь (когда заказчик разбогатеет, даст много денег и скажет: "хочу систему без багов и.... пожалуйста, не спешите" )
LCR>Высказывание "Если юнит-тестов нет, то программа не работает" — это догма. И как любая другая догма она является ложной, поскольку не учитывает многообразие реального мира.
Неа, она не является ложной, чистая правда. Однако, все многообразие реального мира она действительно не учитывает, надо так: "Если юнит-тестов нет, то программа не работает, а если юнит-тесты есть, то тоже не работает". Вот такие пироги
Здравствуйте, FDSC, Вы писали:
FDS>Оффтопик: где у Стругацких эта цитата?
СКАЗКА О ТРОЙКЕ
ИСТОРИЯ НЕПРИМИРИМОЙ БОРЬБЫ ЗА ПОВЫШЕНИЕ ТРУДОВОЙ ДИСЦИПЛИНЫ,
ПРОТИВ БЮРОКРАТИЗМА, ЗА ВЫСОКИЙ МОРАЛЬНЫЙ УРОВЕНЬ,
ПРОТИВ ОБЕЗЛИЧКИ,
ЗА ЗДОРОВУЮ КРИТИКУ И ЗДОРОВУЮ САМОКРИТИКУ,
ЗА ЛИЧНУЮ ОТВЕТСТВЕННОСТЬ КАЖДОГО,
ЗА ОБРАЗЦОВОЕ СОДЕРЖАНИЕ ОТЧЕТНОСТИ
И ПРОТИВ НЕДООЦЕНКИ СОБСТВЕННЫХ СИЛ
minorlogic wrote: > Если обрабатываешь енум , проверь что ты обрабатываешь ВСЕ возможные > значения, если вставляешь ключ в мепку , убедись что он уникален , и т.п. > Т.е. покрыть это все юнит тестами просто НЕРЕАЛЬНО !!!
Обычно смотрится покрытие кода — то есть должна быть выполнены все ветки
условий. Обычно это делается без особых проблем.
FDSC wrote: >> > ANS>Мне не совсем понятно, как, в условиях недостатка времени, можно >> > надеятся, что человек протестирует быстрее чем компьютер? >> > Лекго и просто: тестировщиков побольше нанять, они стоят дешевле чем >> > программист, который сделает хороший ЮТ > C>Если это GUI-приложение, то еще можно. А если приложение — это компилятор? > Хм. И как его протестировать Unit тестами?
Так и тестируется пишутся unit-тесты для определенных частей. Например,
у меня так тестируется разворачивание переменных и т.п.
Cyberax,
>> A> Отсюда и рождается болезненное восприятие изменения этого кода, >> потому как неизвестно как себя поведёт этот код при банальных изменениях >> в нём, а уж о сложных и говорить нечего, а тесты позволяют видеть как >> ведёт себя код при изменениях. >> Свежий код меняется достаточно легко — мы его только что написали и >> помним все трещинки. C>Как раз большая часть ошибок происходит из-за того, что свежий код C>ломает другой код. Юнит-тесты как раз повзоляют это выловить и по C>горячим следам тут же исправить.
Давай разберёмся, что это за гипотетический "другой код"?:
1. Библиотечный — здесь количество ошибок напрямую зависит от умения обращаться с библиотеками, и крайне не рекомендуется использовать библиотеки непроверенным способом, я об этом упоминал.
2. Наш код — здесь возникает вопрос: откуда взялось неизвестное зацепление с кодом, который мы писали месяц назад? Вероятно мы наколбасили уже целых 10Мб и основательно забыли и не записали о неочевидных условиях, в которых работают классы из "первого" мегабайта и неявных связях между ними. И теперь в новом классе мы создали нечто, что нарушило гармоничную работу тех классов... Не спорю, такое возможно. Но очень уж натянуто выглядит это... особенно для кода месячной давности.
Поскольку в прораммировании нет места злым духам, то имеется вполне материальная связь между новым кодом и старым. Откуда взялась эта связь? Намёк на архитектуру: "Вася, зачем тебе доступ к этой коллекции?".
Почему она неочевидна? Намёк на соглашения и комментарии: "Петя, назови методы retrieve*, а не xxx!".
Наконец, если старые классы ломаются, то может быть это неважно? Важный код мы всё-равно тронем, когда будем тестировать всё приложение. Приложение неправильно работает при вытаскивании "соски" во время установки соединения? Обеспечьте хорошей связью. Во время работы при удалении файла с конфигурацией приложение некорректно ведёт себя? Простите, но не удаляйте файл, и всё будет нормально
Как видишь, можно и без ЮТ контролировать такие ошибки, причём опыт написания ЮТ у меня тоже перед глазами: когда встал очередной вопрос недостаточного покрытия тестами в одном из длительных проектов, то на создание дополнительных тестов было выделено 2 (!) недели. А написание тестов с нуля? Даже одновременно с кодом? Возможно, что (тесты + отладка < отладки), но определённо не в нашем случае.
Но впрочем, я повторяю свои мысли изначального сообщения.
vvaizh,
LCR>>Тебе не трудно будет привести примерчик, что за параметры и что за xml. Хотя бы с высоты птичьего полёта?
V>необязательно xml V>достаточно просто уметь получить результат запроса к базе данных в виде текста V>например так: V>...img...
V>пример описывается тут: V>http://izh-test.sourceforge.net/php_pages.html
Да, спасибо, но! Вся разница со способом сравнения с эталонным выводом в том, что здесь тестовый вывод выдирается из БД и над ним производятся некие вычисления?
Как это облегчит рутинность создания юнит-тестов? Нам теперь нужно сформировать (1) эталонный вывод, (2) тесты, (3) вычисления над тестовым выводом. (Процедуру сравнения с эталонным выводом будем считать тривиальной, хотя опять же не факт).
И этот комплекс мер избавляет от рутины при написании ЮТ?
ie,
ie>Отличный анализ!
Спасибо.
ie>Добавлю свои 5 копеек в качестве истории последних пары дней. ie>{Очень интересная жизненная история}.
LCR>>Высказывание "Если юнит-тестов нет, то программа не работает" — это догма. И как любая другая догма она является ложной, поскольку не учитывает многообразие реального мира.
ie>Неа, она не является ложной, чистая правда. Однако, все многообразие реального мира она действительно не учитывает, надо так: "Если юнит-тестов нет, то программа не работает, а если юнит-тесты есть, то тоже не работает". Вот такие пироги
Здорово!
Твоя мысль согласуется с теми же Фаулерами, Беками и прочими: они говорят, чтобы мы вообще обложились тестами по самую макушку: юнит-, интеграционные, регрессионные, стресс-тесты, причём задействована должна быть каждая строчка в программе. Тогда можно с некоторой уверенностью сказать, что программа работает... Но всё это очень трудоёмко
FDSC,
FDS>Т.о. ЮТ не есть хорошо. Есть хорошо комплексное автоматизированное тестирование вариантов использования.
Здесь тоже не всё идеально, но в принципе согласен.
FDS>Оффтопик: где у Стругацких эта цитата? Сказка о тройке (2).
имхо, перманентно — для программы нужны тесты только системные, которые проверяют, что основные задачи — до сих пор работают.
юнит-тесты нужны только, если модуль — хандрит, причем как только модуль заработал, юнит-тесты можно выкинуть в помойку.
это наблюдение основывается на том, что если модуль уже написан (уже прошел активную фазу развития), то дальше он дохнет редко — и если уж отваливается, то отваливается полностью, когда произошло какое-то изменение в окружении.
системные тесты могут представлять из себя стенд(ы) — на которых прогоняется близкая к правде работа, соответственно если работа выполнилась — значит мы считаем, что программа до сих пор работает хорошо.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>vvaizh,
LCR>>>Тебе не трудно будет привести примерчик, что за параметры и что за xml. Хотя бы с высоты птичьего полёта?
V>>необязательно xml V>>достаточно просто уметь получить результат запроса к базе данных в виде текста V>>например так: V>>...img...
V>>пример описывается тут: V>>http://izh-test.sourceforge.net/php_pages.html
LCR>Да, спасибо, но! Вся разница со способом сравнения с эталонным выводом в том, что здесь тестовый вывод выдирается из БД и над ним производятся некие вычисления?
зачем производить вычисления?
вот у тебя отработала некая часть системы..
что после неё должно измениться?
как ты это проверяешь при ручной отладке?
наверно запрос какой нибудь тестовый выполняешь?
вот и тут также абсолютно..
ты почитай пример там всё просто описано..
если процесс регистрации пользователя, то должна добавиться запись в таблице пользователей
её запросом и смотришь..
LCR>Как это облегчит рутинность создания юнит-тестов?
1. это облегчит написание контрольного сравнения с эталоном, так как теперь нужно не для каждого скалярного компонента большой структуры которая обыкновенно получается на выходе писать проверку (в описанном случае проще просто распечатать содержимое всего массива например вместо того чтобы отдельно проверять его размер и значение полей (ещё хуже если там опять нескалярные значение лежат))
2. это облегчает обновление эталонных данных когда это необходимо (просто банальным объявлением новых отличающихся резальтатов эталонными)
LCR>Нам теперь нужно сформировать (1) эталонный вывод,
нам не нужно его "формировать"
нам нужно :
1. запустить один раз тест,
2. проконтроллировать глазками что тест на выход выдал правильный результат
3. банально объявить этот результат эталонным
всё это выполняется буквально несколькими нажатиями клавиши/мышки
LCR>(2) тесты,
ну а как вы результат заказчику сдаёте?
неужели не тестируете перед сдачей?
в идеале просто средство должно быть таким чтобы трудозатраты на обычное
"предперворелизноелишьбыотмазаться" тестирование были практически теми же..
но тест был готов автоматический..
LCR>(3) вычисления над тестовым выводом. (Процедуру сравнения с эталонным выводом будем считать тривиальной, хотя опять же не факт).
вычисления требутся довольно редко наверно раз на 3-5 тестов
когда в выводе могут присутствовать недетерминированные результаты, типа времени или недетерминированной сортировки
таких ситуаций достаточно мало и как с ними обходиться в принципе понятно
(например в mysql-ном тест suite встроена возможность выполнять regexp-ы над выводом)
LCR>И этот комплекс мер избавляет от рутины при написании ЮТ?
не избавляет, но существенно уменьшает рутину
сводя её почти до тех же трудозатрат, которые и так необходимы при обычной отладке..
просто обычно при недостатке времени тестируются считанные еденицы вариантов использования системы "в целом",
не заморачиваясь на отдельных частях..
т.е. отлаживать начинают с большего, а не с меньшего..
тут то и должно быть средство которое легко может превратить такое функциональное тестирование
в автоматическое для дальнейшего использования..
DarkGray,
DG>имхо, перманентно — для программы нужны тесты только системные, которые проверяют, что основные задачи — до сих пор работают.
DG>юнит-тесты нужны только, если модуль — хандрит, причем как только модуль заработал, юнит-тесты можно выкинуть на помойку.
DG>это наблюдение основывается на том, что если модуль уже написан (уже прошел активную фазу развития), то дальше он дохнет редко — и если уж отваливается, то отваливается полностью, когда произошло какое-то изменение в окружении.
Интересное наблюдение. Только некоторые участники утверждают (в частности EAO и Cyberax), что они (ЮТ) нужны ещё для контроля при эволюционном изменении модуля ("я тут поменял, а там отвалилось"). Впрочем, здесь картина зависит от конкретной ситуации, на этот счёт мы с Cyberax-ом бодались здесь
.
DG>системные тесты могут представлять из себя стенд(ы) — на которых прогоняется близкая к правде работа, соответственно если работа выполнилась — значит мы считаем, что программа до сих пор работает хорошо.
+1
Автора цитировать не буду, поскольку с большей частью его выводов интуитивно согласен. Есть области разработки, где тестирование действительно полезно — это пожалуй библиотеки и алгоритмы, но все же помимо ИМХОв людей участвующих в дискуссии хотелось бы получить некую статистику.
Кто нибудь знает статистику по проектам выполняемым с использованием юнит тестов ? Т.е. не теоретические выкладки, а именно статистика по реальным проектам.
LCR>Интересное наблюдение. Только некоторые участники утверждают (в частности EAO и Cyberax), что они (ЮТ) нужны ещё для контроля при эволюционном изменении модуля ("я тут поменял, а там отвалилось"). Впрочем, здесь картина зависит от конкретной ситуации, на этот счёт мы с Cyberax-ом бодались здесь
Здравствуйте, Cyberax, Вы писали:
C>minorlogic wrote: >> Если обрабатываешь енум , проверь что ты обрабатываешь ВСЕ возможные >> значения, если вставляешь ключ в мепку , убедись что он уникален , и т.п. >> Т.е. покрыть это все юнит тестами просто НЕРЕАЛЬНО !!! C>Обычно смотрится покрытие кода — то есть должна быть выполнены все ветки C>условий. Обычно это делается без особых проблем.
Без проблем оттестировать DLL у которой одна функция типа Render, которая читает определенные данные и рендрит . запросто , устроить тест который проверить всю корректность рендеринга , да просто плевое дело.
Здравствуйте, DarkGray, Вы писали:
DG>это наблюдение основывается на том, что если модуль уже написан (уже прошел активную фазу развития), то дальше он дохнет редко — и если уж отваливается, то отваливается полностью, когда произошло какое-то изменение в окружении.
У меня на практике были баги которые обнаруживались через 6 лет. А такие вещи хрен найдешь, из-за того что считается что модуль работает. У unit-тестов все таки большой плюс в том, что это уже готовое api чтобы проверить то или иное предположение.
DG>системные тесты могут представлять из себя стенд(ы) — на которых прогоняется близкая к правде работа, соответственно если работа выполнилась — значит мы считаем, что программа до сих пор работает хорошо.
Ни один набор функциональных тестов не может заменить человека-тестера. Иногда приходят ошибки, которые проявляются в такой последовательности действий, о которых вообще не догадывался. Та что считать что программа работает на функц. тестах хорошо — не есть хорошо. Лучше уж быть готовым ко всему.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>когда встал очередной вопрос недостаточного покрытия тестами в одном из длительных проектов, то на создание дополнительных тестов было выделено 2 (!) недели. А написание тестов с нуля? Даже одновременно с кодом? Возможно, что (тесты + отладка < отладки), но определённо не в нашем случае.
Сколько ни пробовал покрыть имеющийся проект юнит-тестами — так пока и не получилось ни разу. Не говоря уже чтобы хорошо было. А вот писать их во время написания кода — как раз гораздо легче и мало отвлекает...
Здравствуйте, fmiracle, Вы писали:
F>Здравствуйте, FDSC, Вы писали:
FDS>>1. Когда я писал в VS 6.0 (на C++, понятно) я попытался сделать ЮТ: результат был поразительным: мой код был настолько отстойным, что отстойней просто некуда. Иногда создавалось такое впечатление, что я просто забыл, что и как хотел написать в коде. ЮТ просто выбили меня из задачи. После ещё нескольких попыток я понял, что ЮТ не для меня.
F>У меня тоже такое было. И тесты фиговые получались, и код корежило ужасно, чтобы обеспечить доступ тестам к нужной (как мне тогда казалось) информации. Забросил я их. Потом, набравшись опыта вообще и прочитав разных книг, включая книги про ЮТ — решил, что можно опять попробовать, ибо достало править глупые ошибки, для обнаружения которых надо забить длинную экранную форму в программе... И вот сейчас они уже начинают облегчать мне работу.
У меня не так: я ничего в архитектуре не менял. Просто меня выбивало из задачи.
F>Я, правда, перестал думать, что ЮТ обеспечат меня надежной и безошибочной программой, а стал относиться к ним как к средствую повышения скорости отладки. Точнее — скорости обнаружения и локализации ошибок. А так же — средство поразмыслить над тем, что же я вообще пишу — ЮТ я пишу одновременно с кодом (то сперва код, потом тесты, то наоборот — по ситуации, но примерно в одно время) — это не выбивает меня из потока, наоборот позволяет рассмотреть ситуацию с разных сторон и подумать о возможных слабых местах, а потом сразу посмотреть — нормально оно заработало оно или нет. Часто код и тесты вообще пишутся параллельно — тут придумал новый тест — и даже без запуска понял, что эта ситуация в коде не предусмотрена — пошел дописал, заодно придумал еще тест.
Да, такое действительно бывает. Хотя я пока обхожусь без автоматизации.
minorlogic wrote: > C>Обычно смотрится покрытие кода — то есть должна быть выполнены все ветки > C>условий. Обычно это делается без особых проблем. > Без проблем оттестировать DLL у которой одна функция типа Render, > которая читает определенные данные и рендрит.
Если функция читает и рендерит данные — то это пример плохого
проектирования. Либо надо тестировать уже не функцию Render, а
внутренние функции библиотеки (типа readData, renderData).
При этом корректность рендеринга проверять обычно бессмысленно.
Здравствуйте, Cyberax, Вы писали:
C>FDSC wrote: >>> > ANS>Мне не совсем понятно, как, в условиях недостатка времени, можно >>> > надеятся, что человек протестирует быстрее чем компьютер? >>> > Лекго и просто: тестировщиков побольше нанять, они стоят дешевле чем >>> > программист, который сделает хороший ЮТ >> C>Если это GUI-приложение, то еще можно. А если приложение — это компилятор? >> Хм. И как его протестировать Unit тестами? C>Так и тестируется пишутся unit-тесты для определенных частей. Например, C>у меня так тестируется разворачивание переменных и т.п.
НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в графе?
FDSC,
C>>Так и тестируется пишутся unit-тесты для определенных частей. Например, C>>у меня так тестируется разворачивание переменных и т.п.
FDS>НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в графе?
Обычно вычисляемый вывод сравнивается с ожидаемым.
Либо влазить в кишки... Это легко в данном случае, ибо алгоритмы Флойда и Дейкстры изучены вдоль и поперёк, и есть леммы о том, что некоторые соотношения сохраняются на каждом шаге алгоритма. Их можно вот проверять в принципе.
Но в более сложных случаях (я видел описание одного алгоритма для задачи теории расписаний — 40 страниц!) — только вышеуказанным способом.
Lazy Cjow Rhrr wrote: > Давай разберёмся, что это за гипотетический "другой код"?: > 1. Библиотечный — здесь количество ошибок напрямую зависит от умения > обращаться с библиотеками, и крайне не рекомендуется использовать > библиотеки непроверенным способом, я об этом упоминал.
Угу, согласен. Библиотеки нет смысла тестировать.
> 2. Наш код — здесь возникает вопрос: откуда взялось неизвестное > зацепление с кодом, который мы писали месяц назад? Вероятно мы > наколбасили уже целых 10Мб и /основательно забыли и не записали о > неочевидных условиях/, в которых работают классы из "первого" мегабайта > и неявных связях между ними.
Так ведь записывать ВСЕ неявные связи — невозможно. В моем примере
неявная связь была в структуре одного из списков. Таких примеров у меня
достаточно много.
> И теперь в новом классе мы создали нечто, > что нарушило гармоничную работу тех классов... Не спорю, такое возможно. > Но очень уж натянуто выглядит это... особенно для кода месячной давности.
У меня такое достаточно часто бывает, особенно в командной работе.
В нем есть куча случаев и этот код, вдобавок, еще и является performance
bottleneck'ом. При добавлении новой оптимизации нужно смотреть на то,
что она не сломает какой-то частный случай. Без тестов это делать было
бы оооочень жутко.
> Намёк на архитектуру: "Вася, зачем тебе доступ к этой коллекции?". > Почему она неочевидна? Намёк на соглашения и комментарии: "Петя, назови > методы retrieve*, а не xxx!".
Ну так в том-то и дело, что часто доступ к коллекции вполне очевиден и
нужен. В примере со stacktrace'ом была зависимость на структуру списка
фреймов — вполне логичная для интерпретатора вещь.
> Наконец, если старые классы ломаются, то может быть это неважно? Важный > код мы /всё-равно/ тронем, когда будем тестировать всё приложение.
Вопрос в том когда оно обнаружится. Вдобавок, при работе в
команде наведенные ошибки могут привести к тому, что отлаживать твой код
будет уже другой человек и займет это у него больше времени (скорее всего).
> А написание тестов с нуля?
В существующем проекте — скорее всего неоправдано.
> Даже одновременно с кодом? Возможно, что (тесты + отладка > < отладки), но определённо не в нашем случае.
Опять же, случаи бывают разные. Но если код поддается юнит-тестированию,
то оно обычно сокращает сроки разработки.
FDSC wrote: > C>Так и тестируется пишутся unit-тесты для определенных частей. Например, > C>у меня так тестируется разворачивание переменных и т.п. > НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в > графе?
Какой алгоритм? Волновик?
Пишем тест, который вызывает попадания во все ветки условий (их там
совсем немного).
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>FDSC,
C>>>Так и тестируется пишутся unit-тесты для определенных частей. Например, C>>>у меня так тестируется разворачивание переменных и т.п.
FDS>>НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в графе? LCR>Обычно вычисляемый вывод сравнивается с ожидаемым.
LCR>Либо влазить в кишки... Это легко в данном случае, ибо алгоритмы Флойда и Дейкстры изучены вдоль и поперёк, и есть леммы о том, что некоторые соотношения сохраняются на каждом шаге алгоритма. Их можно вот проверять в принципе.
LCR>Но в более сложных случаях (я видел описание одного алгоритма для задачи теории расписаний — 40 страниц!) — только вышеуказанным способом.
Вот в этом вся и проблема. Для того что бы писать ЮТ нужна или хорошая теория, которая позволяет проверить по косвенным данным правильность выполнения (а если теории нет, ведь задачка сразу очень тяжёлой становиться) или проверять по посчитанному вручную набору данных.
В итоге получается, что, лично у меня, все ЮТ сводятся к автоматизированной загрузки заранее подготовленных в ручную save'ов и автоматизированному же сравнению сохранённого результата с эталонным.
Здравствуйте, Cyberax, Вы писали:
C>FDSC wrote: >> C>Так и тестируется пишутся unit-тесты для определенных частей. Например, >> C>у меня так тестируется разворачивание переменных и т.п. >> НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в >> графе? C>Какой алгоритм? Волновик?
C>Пишем тест, который вызывает попадания во все ветки условий (их там C>совсем немного).
Не понял, что проверяется и что от этого будет? Ведь я могу случайно (у меня такое действительно было) вместо < поставить >, и ЮТ уже ничем не поможет тогда.
У меня в алгоритме никаких веток, собственно нет. Там можно проверить только что вообще по всем узлам прошёл. Да и то будут ложные срабатывания, если граф несвязный. Для меня ложные срабатывания в ЮТ самая большая проблема была, когда я ими пытался пользоваться.
Впрочем, я только для примера привёл именно этот алгоритм.
FDSC wrote: > C>Пишем тест, который вызывает попадания во все ветки условий (их там > C>совсем немного). > Не понял, что проверяется и что от этого будет? Ведь я могу случайно (у > меня такое действительно было) вместо < поставить >, и ЮТ уже ничем не > поможет тогда.
Для этого надо сравнивать результирующие данные с эталоном.
> У меня в алгоритме никаких веток, собственно нет. Там можно проверить > только что вообще по всем узлам прошёл. Да и то будут ложные > срабатывания, если граф несвязный. Для меня ложные срабатывания в ЮТ > самая большая проблема была, когда я ими пытался пользоваться.
Проблема с алгоритмической корректностью — это уже совсем другая история.
Юнит-тесты нужны для проверки непосредственно правильности кода.
Здравствуйте, Mirrorer, Вы писали:
LCR>>5. Статическая типизация в сочетании с IDE работает удовлетворительно и без тестов. M>+1 Но статическая типизация в сочетании с ИДЕ и с юнит тестами работает лучше чем удовлетворительно.
Мне кажется, что это (выше) ключевой момент дисскуссии вызывающий несогласие в станах оппонентов.
Суть его проста.
1. Есть люди которые вообще считают тестирование пустой тратой времени. Таких очень мало и скорее всего они просто по другому понимают этот термин. Тестирование у них есть но выглядит оно по другому.
2. Есть люди которые говорят как ты. Если высказаться более конкретно то это будет звучать так "Любые средства повышающие надежность кода хороши и полезны." При этом по хорошему надо добавлять "...если при этом они не создают проблем больше чем решают."
3. Есть люди которые считают, что без юнит-тестов жить нельзя и все кто их не делает м... ну, опистим это . В большинстве влучаев такие люди пишут на скриптовых или небезопасных (почти синоним С++ ) языках и не используют продвинутых IDE.
4. Есть настоящие маньяки TDD/XP. Эти вообще ничего не аргументируют. Их высказывания зачастую верны, но в общей массе они представляют религиозную пропаганду. В их речи нужно верить или нет.
Кстати, часто упоминаемый Фаулер мною относится ко второй категории, хоят многие считают его членом четвертой. Все же Фаулер довльно разумен и не столь радикален. Он продвигает многие средсвта повышающие качество кода. TDD только одно из них. Например, DSL-и он продвигает не хуже.
Так вот проблема в том, что многие из тех кто тут во всю ставит оценки своим оппонентам на самом деле всего лишь пытаются прикрыть свои радикальные взгляды.
Они используют юнит тесты для защиты, например, нетипизированных и опасных языков. В обсуждении тем связанных со статической типизации они постоянно принижают ее значения кивая на то что мол без юнит-тестов вообще не жить, а раз так то зачем тогда все эти проверки комиилятора. Все равно юнит-тесты все проверят.
Я тоже придерживаюсь позиции из второго пункта. Более того считаю что статическая типизация и безопасный язык даже более важны чем сами юнит тесты. Хотя я не склонен противопоставлять одно ругому. Тесты проверяют динамику, а система типов статику.
Если взять тот же рефакторинг, то по моему мннеию статическая типизация и поддержка IDE здесь играют даже большую роль. Конечно юнит-тесты могут только помочь рефакторингу добавив контроля за ситуацией, но все же они не способны именно помочь и темболее автоматизировать рефакторин. Меж тем если рефакторинг можно произвести силами IDE, то никакой дополнительный контроль в общем-то и не потребуется, а сам рефакторинг будет произведен в щитанные секунды. Те кто использует автоматизированный рефакторинг повседенвно так к нему привыкли, что даже незадумываются над тем, что их оппоненты не понимают этог, а стало быть оба лагеря недооценивают значимость автоматического рефакторинга.
Но даже если автоматический рефакторинг невозможен статическая типизация повзоляет существенно сократить объем работы и в особенности объем отладки, так как многие ошибки автоматически отлавливаются системой типов. При этом компилятор (особенно если он хороший) показывает места ошибок и содествует пониманию совершенной ошибки. Это позволяет устранять ошибки быстрее. Конечно, мы тратим какое-то время на борьбу с ошибками компиляции, но если это не бессимысленные награмождения ошибок вызваемых С++-компилятором в следствии вольной трактовки очередного супер-шаблона, то мы довольно быстро устраняем их. При этом значительно согращается этап отладки. Это намного лучше чем несработавший юнит-тест. Юнит тест только отлавивает ошибку. И не всегда из этого понятно в чем ошибка, и как ее отловить.
Далее юнит-тесты все же сами по себе вызвают проблемы. Как бы кто не говорил, что это все мелочи, но юнит-тесты сами требуют написания, отладки и рефакторинга. В случае рефакторина они усложняют этот процесс. Бывает даже так, что тест путает. Ведь мы априори воспринимаем тест как верный. А возмоно ошибка в нашем предположении. При этом видя зеленый кружочек мы думаем "Все ОК! Ошибок нет, или ошибка просто не охвачена тестами. Будем копать...", а на самом деле ошибка находится в юнит-тесте и программист подтасовал результат кода под эту ошибку. Причем в рамках тество пробелем нет, но в реальном использовании они таки могут вылезти. Это уже наложенная ошибка. Так называемая — ошибка второго порядка.
Ну и главное, юнет-тесты не отлавливают всех ошибко и не делают программу корректной. Они позволяют ввести дополнительный контроль. Это нужно четко понимать. А многие поклонники TDD молятся на них.
Есть разные задачи. Для одних юнит-тесты удобны. Для других неприменимы. Для теретих бессмысленны. Так нельзя проверить ГУИ юнит-тестами. Создание МОК-объектов тут является полнешей глупостью. МОК-объекты будут заменять ГУИ. Так что мы будем тестировать прикладной код, а не ГУИ. Меж тем для тестирования ГУИ есть мощьные средства втоматизации (стоящие не мало денег, однако). Так же бесполезны юнит-тесты при разработке систем с динамической логикой. Точнее они не бесполезны. Выгоду от юнет-тестов можно получить и тут. Вед динамическая логика состоит из частей. Эти части тоже нужно писать, отлаживать и контролировать. Но к сожалению проверить юнит тестами кореектность таких систем нельзя. Тут нужны пакетные тесты содержащие много сложных сочетаний. Конечно и их можно назвать юнит-тестами, так как мы в итоге проверям результат пакетного теста с ожидаемым, но вот написать такой тест невозможно, да и не является он уже "Юнит". Он контролирует уже массу аспектов, а не какй-то один.
Так вот тестирование важно. Без него никуда. Но как не странно бывает (и часто), что лучшим тестированием является прикладное использование. Я часто замечал, что продукты лучше если их используют те кто пишет и если пользователи могут напрямую воздействовать на разработчиков.
Так что юнит-тесты — это инструмент повышения качества кода. Не болше и не меньше. Не надо низводить его до полной никчемности, но и не стоит делать из него религию и строить свою разработку исключительно отталкиваясь от них.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Не волнуйтесь. Если Вам удается работать без юнит-тестов и при этом хорошо зарабатывать, продолжайте в том же духе. Кто такие эти Эскель, Фаулер, Бек ? Они — Ваши клиенты ? Они Вам плотют деньги ? Если нет, то они не выражают Вам требования, а лишь высказывают свое мнение опираясь на свой опыт. С их мнением можно считаться. А можно не считаться. А уж опыт — он у всех очень очень разный.
Что касается юнит-тестов. Это всего-лишь одна из методик, которая может облегчить Вам жизнь. А может не облегчить. Применять ее или нет — решать Вам. По моему опыту, юнит-тесты обладают следующими достоинствами и недостатками:
Достоинства
1) Заставляют продумывать заранее, что нужно запрограммировать (test-first).
2) Заставляют строить модульные системы.
3) Действительно улучшают качество выходного продукта.
4) Создают приятное (ложное) ощущение, что проект работает верно.
Недостатки
1) Вводят в ступор (тут без теста бы сообразить, с какого вообще конца браться, а ты гришь test-first...)
2) Требуют дополнительных усилий на их написание
3) Стремятся сделать проект менее гибким, а именно:
3.1) Требуют времени на пожжержание дополнительного кода
3.2) Требуют времени на согласование изменений в коде и тестах
4) Создают ложное (приятное) ощущение, что проект работает верно.
В моей практике очень часто возникают такие ситуации, когда изменения в коде влекут такие катастрофические изменения тестов, что я просто начисто вырезаю с мясом целые тест-сюиты, так как не вижу смысла их поддерживать в дальнейшем.
Не поддавайтесь на провокацию о 100% покрытии приложения тестами. Это утопия. Не бывает 100% покрытия по вполне понятным причинам комбинаторной сложности задачи. Юнит-тесты немного, конечно, снижают комбинаторную сложность за счет того, что работают не со всей программой, а с ее частями, но все равно, сложность написания тестов в неокоторых случаях превосходит сложность реализации. А это глупо. Лучше я два раза напишу одну и ту же программу по разному и буду сверять результаты — это будет надежнее.
Да и вообще. Вы сами уже ответили на все вопросы, когда сказали что worse is better. Мы будем делать то, что надо [клиенту], а того, что не надо [клиенту] мы делать не будем. А ему часто по барабану все эти тесты, красивая архитектура, запредельное качество. Клиент у нас с Вами — не министерство обороны с встроенными системами на подлодках, клиент у нас простодушный Большой Босс Владеющий Банками Заводами Пароходами, делайте то что ЕМУ важно, а на то, что программа вываливается в корку, когда пытаешься на сааамый удаленный пункт меню нажать он (клиент) даже внимания не обратит. А если обратит, честно признаем, что она (программа) не идальна, у всех свои недостатки. Клиент поймет.
Все. Написал бы больше, но нужно идти циферки складывать и денежки со счета на счет пересыпать... Большого Босса ублажать
Проблему подметил верно, а вывод не верный сделал. Рефакторить надо для уменьшения сложности решения. Для увеличения ясности. Эти факторы не могут затянуть время разработки проекта. Если проект сложный, то уменьшение его сложности без потери функционала — это увеличение скорости его завершения. Ведь в ты экономишь не на мелочах, а что называется повровым методом.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, DarkGray, Вы писали:
DG>юнит-тесты нужны только, если модуль — хандрит, причем как только модуль заработал, юнит-тесты можно выкинуть в помойку.
По-моему, юнит-тесты можно применять как средство отладки сложных вещей. Например, в приложен может быть не так просто воспроизвести некое состояние. А юнит-тест может делать это за считанные милисекунды.
Удалять его после завершения отладки смысла нет. Можно просто ввести более общие тесты, а юнит-тесты проганять только изредка или когда нужно вернуться к работе с тем состоянием.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, mishaa, Вы писали:
M>Угу, в частности про то что в этом месте может отвалится помнит только юнит тест.. а люди как правило забывают.
Большой пакетный тест тоже может помнить. Например, если мы пишем компилятор, то о том, что что-то отвалилось напомнит попытка скомпилировать самого себя или другой объемный проект.
Так что юнит тесыт тут соревнуются скорее с системой типизации, та как они могут более четко указать на проблему. И при таком взгляде на проблему юнит-тесты по сути являюся плохо реализованными системами ограничения типов (контрактов).
На контракты можно смореть как на продолжение описания типа. Просто сам тип это структурный контракт, а "конктракт" — это алгеброический контракт проверяющий модель поведения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Laughing_Silencer,
L_S>Автора цитировать не буду, поскольку с большей частью его выводов интуитивно согласен. Есть области разработки, где тестирование действительно полезно — это пожалуй библиотеки и алгоритмы, но все же помимо ИМХОв людей участвующих в дискуссии хотелось бы получить некую статистику.
L_S>Кто нибудь знает статистику по проектам выполняемым с использованием юнит тестов ? Т.е. не теоретические выкладки, а именно статистика по реальным проектам.
+1;
особенно мне интересно было бы увидеть статистику по видам ошибок в условиях современных средств разработки. Нигде не нашёл...
borisman3,
B>Не волнуйтесь. Если Вам удается работать без юнит-тестов и при этом хорошо зарабатывать, продолжайте в том же духе.
B> А ему часто по барабану все эти тесты, красивая архитектура, запредельное качество. Клиент у нас с Вами — не министерство обороны с встроенными системами на подлодках, клиент у нас простодушный Большой Босс Владеющий Банками Заводами Пароходами, делайте то что ЕМУ важно, а на то, что программа вываливается в корку, когда пытаешься на сааамый удаленный пункт меню нажать он (клиент) даже внимания не обратит. А если обратит, честно признаем, что она (программа) не идальна, у всех свои недостатки. Клиент поймет.
Положа руку на сердце хотелось бы делать что-нибудь хотя бы приблизительно напоминающее (по надёжности) AXD 301 Но ресурсы малы и возможности не те...
B>Все. Написал бы больше, но нужно идти циферки складывать и денежки со счета на счет пересыпать... Большого Босса ублажать
Да, да, я тоже примерно это же.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
A>>Если код не протестирован, то как можно говорить о том, что он работает правильно? LCR>Очень даже можно. Как я и говорил, убедиться в том, что он работает, можно наличием другого тестирования. Проверяются все варианты использования, какие нужны, а работа программы при -273'C не требуется. Предлагаешь вместо создания руля и приборной доски устраивать крэш-тесты?
Опять тоже самое упущение, мы не проверяем работу программы, мы проверяем правильность работы кода. С этой стороны также неверно говорить о тестировании GUI, потому как GUI — это не код. Нельзя тестировать БД — это тоже не код. Юнит-тестами тестируем только код.
(На самом деле фраза построена специально, чтобы напомнить стиль книг Фаулера и Бека, но её не надо воспринимать в таком виде Главное идею обобщить.)
Есть ещё такая метафора для юнит-тестирования как "проверка грамматических правил". Орфография в тексте проверяется фактом компилирования программы, а грамматика — покрывается правилами языка (тестами). И затем если вставить куда-то в середину фразы дополнительные слова, то редактор в случае грамматически неверно построенных предложений подчеркнёт предложение и его можно как-то исправить, до тех пор пока ошибка не исчезнет. Вот только для кода нельзя построить список конкретных правил и этим занимается программист, а для письменности — это всё же возможно. Вот я грамматические ошибки в тексте очень не люблю .
Ну а метафора, как и любая аналогия — неверна по определению
Для тестирования работоспособности программ существуют функциональные тесты, которые и правда могут быть заменены бригадой QA.
A>> Отсюда и рождается болезненное восприятие изменения этого кода, потому как неизвестно как себя поведёт этот код при банальных изменениях в нём, а уж о сложных и говорить нечего, а тесты позволяют видеть как ведёт себя код при изменениях. LCR>Свежий код меняется достаточно легко — мы его только что написали и помним все трещинки.
Угу, так как я часто пишу реализации алгоритмов (криптография в основном), то свежий код даже только что написанный не так то и легко запоминать по всем трещинкам. Особенно когда опасность его сломать заключается практически в любом изменении. На этом опыте просто хорошо очень это замечается, но я переношу это и на другие проекты, хотя там это не так заметно, и действительно, чтобы сломать только что написанный код в таких проектах нужно постараться.
A>>Тесты прежде всего нужны, чтобы было психологически легче изменять уже написанный код и удостоверятся, что при этом ничего не сломалось. Автоматический рефакторинг заменяет тесты при нефункциональных изменениях кода (то есть в средах, где автоматический рефакторинг отсутствует, уверенность работоспособности кода остаётся только на тестах). При функциональных же изменениях без тестов на работоспособность уже не обойтись. LCR>Ты прав, и это не противоречит моим словам — в длительной перспективе тесты необходимы. Я же говорил о срочных проектах.
Понятие срочности очень растяжимое. Если "срочное" — это утилита, которая пишется два дня, выкидывается на использование и забывается, то конечно согласен, что тут тесты просто не успевают появиться (если конечно не используется методика TDD). Но если программа далее передаётся ещё и QA и затем наверняка возвращается для исправления ошибок, то, о каком же таком "срочном" проекте идёт речь?
Еще, например я не пишу тестов для прототипов, потому как там действительно они только мешают быстро создавать эти самые прототипы.
P./S.: Напоследок ещё такое наблюдение:
Отсутствие успешно отрабатывающих юнит-тестов говорит о халатности работы в команде, практически точно также как и коммит в репозиторий некомпилирующегося кода.
Здравствуйте, VladD2, Вы писали:
VD>Так вот тестирование важно. Без него никуда. Но как ни странно бывает (и часто), что лучшим тестированием является прикладное использование. Я часто замечал, что продукты лучше если их используют те кто пишет и если пользователи могут напрямую воздействовать на разработчиков.
Из этого следствие: программы должны писать пользователи, а не программисты
Здравствуйте, Cyberax, Вы писали:
C>minorlogic wrote: >> C>Обычно смотрится покрытие кода — то есть должна быть выполнены все ветки >> C>условий. Обычно это делается без особых проблем. >> Без проблем оттестировать DLL у которой одна функция типа Render, >> которая читает определенные данные и рендрит. C>Если функция читает и рендерит данные — то это пример плохого C>проектирования. Либо надо тестировать уже не функцию Render, а C>внутренние функции библиотеки (типа readData, renderData).
C>При этом корректность рендеринга проверять обычно бессмысленно.
Вот на эту мысль я и пытался навести , что тестировать наиболее удобно маленькие отдельные модуле , а если сам тест встроен еще и в исполняемый код , то это почти идеально. И разделять юнит тесты в некое отдельно приложение не всегда разумно.
Т.е. Я не говорю о том что ЮТ плохи , я говорю о разумном подходе. Например я бы при тестировании смарт поинтера применил несколько подходов
1. АССЕРТЫ внутри реализации.
2. Тесты на функциональность. (копирование самого в себя и т.п.)
3. Тесты со специальными классами , которые подсчитывают к-во копирований конструкторов и деструкторов.
VD>Удалять его после завершения отладки смысла нет. Можно просто ввести более общие тесты, а юнит-тесты проганять только изредка или когда нужно вернуться к работе с тем состоянием.
вот именно: если будет нужен, то его надо будет отрыть в дебрях vcs, сдуть нафталин и заставить работать.
но пока тест не нужен — каждодневно на него тратить время на сопрождение, запуск и трактовку результатов — не имеет смысла.
Cyberax,
>> 2. Наш код — здесь возникает вопрос: откуда взялось неизвестное >> зацепление с кодом, который мы писали месяц назад? Вероятно мы >> наколбасили уже целых 10Мб и /основательно забыли и не записали о >> неочевидных условиях/, в которых работают классы из "первого" мегабайта >> и неявных связях между ними. C>Так ведь записывать ВСЕ неявные связи — невозможно. В моем примере C>неявная связь была в структуре одного из списков. Таких примеров у меня C>достаточно много.
Да, охотно верю, но нам не нужны ВСЕ связи, а только те, которые имеют значение и видны в конечном результате. Погоня за безупречным качеством обходится недёшево и требует совсем иного подхода, ежели у нас.
>> И теперь в новом классе мы создали нечто, >> что нарушило гармоничную работу тех классов... Не спорю, такое возможно. >> Но очень уж натянуто выглядит это... особенно для кода месячной давности. C>У меня такое достаточно часто бывает, особенно в командной работе.
C>Кстати, юнит-тесты еще в другом помогают — вот у нас есть модуль, C>который обрабатывает кучу вариантов. В моем случае это модуль, C>занимающийся раскрытием переменных: C>http://boost.sourceforge.net/boost-build2/doc/html/jam/language.html#jam.language.variables
C>В нем есть куча случаев и этот код, вдобавок, еще и является performance C>bottleneck'ом. При добавлении новой оптимизации нужно смотреть на то, C>что она не сломает какой-то частный случай. Без тестов это делать было C>бы оооочень жутко.
В данном случае бесспорно.
>> Наконец, если старые классы ломаются, то может быть это неважно? Важный >> код мы /всё-равно/ тронем, когда будем тестировать всё приложение. C>Вопрос в том когда оно обнаружится. Вдобавок, при работе в C>команде наведенные ошибки могут привести к тому, что отлаживать твой код C>будет уже другой человек и займет это у него больше времени (скорее всего).
Да, оно может обнаружиться на этапе тестирования пользователем или вообще у клиента. Увы, приходится мириться. Да, неприятно — поэтому уделяется большое внимание 100% проработке требуемых вариантов использования.
Джентельменские соглашения внутри команды исключают то, что править будет другой человек. А пройтись дебаггером по чужому коду — невелика проблема. На крайний случай, можно спросить: "Вася, а вот эти гирлянды ты зачем развесил?".
>> А написание тестов с нуля? C>В существующем проекте — скорее всего неоправдано.
Почему это?
>> Даже одновременно с кодом? Возможно, что (тесты + отладка >> < отладки), но определённо не в нашем случае. C>Опять же, случаи бывают разные. Но если код поддается юнит-тестированию, C>то оно обычно сокращает сроки разработки.
Ну вот о чём и речь. Мне кажется, что у вас условия работы и требования к коду совсем другие.
Andir,
A>Есть ещё такая метафора для юнит-тестирования как "проверка грамматических правил". Орфография в тексте проверяется фактом компилирования программы, а грамматика — покрывается правилами языка (тестами).
Кстати, гораздо чаще я эту метафору (spell-check) слышал применительно к статической типизации.
A>И затем если вставить куда-то в середину фразы дополнительные слова, то редактор в случае грамматически неверно построенных предложений подчеркнёт предложение и его можно как-то исправить, до тех пор пока ошибка не исчезнет. Вот только для кода нельзя построить список конкретных правил и этим занимается программист, а для письменности — это всё же возможно. Вот я грамматические ошибки в тексте очень не люблю . A>Ну а метафора, как и любая аналогия — неверна по определению
В принципе с мыслью согласен, и считаю что данная метафора вполне отражает суть вещей.
A>Для тестирования работоспособности программ существуют функциональные тесты, которые и правда могут быть заменены бригадой QA.
У нас примерно так и делается.
A>>> Отсюда и рождается болезненное восприятие изменения этого кода, потому как неизвестно как себя поведёт этот код при банальных изменениях в нём, а уж о сложных и говорить нечего, а тесты позволяют видеть как ведёт себя код при изменениях. LCR>>Свежий код меняется достаточно легко — мы его только что написали и помним все трещинки.
A>Угу, так как я часто пишу реализации алгоритмов (криптография в основном), то свежий код даже только что написанный не так то и легко запоминать по всем трещинкам. Особенно когда опасность его сломать заключается практически в любом изменении. На этом опыте просто хорошо очень это замечается, но я переношу это и на другие проекты, хотя там это не так заметно, и действительно, чтобы сломать только что написанный код в таких проектах нужно постараться.
Соглашения, архитектура и элементарная культура позволяют в принципе сносно управляться с изменениями в свежем коде. К тому же я не раз подчёркивал, что как только проект начинает "длиться во времени", то нужно уже делать тесты. Чем раньше, тем лучше, но очень рано не получается, потому что сначала есть более приоритетные задачи.
A>>>Тесты прежде всего нужны, чтобы было психологически легче изменять уже написанный код и удостоверятся, что при этом ничего не сломалось. Автоматический рефакторинг заменяет тесты при нефункциональных изменениях кода (то есть в средах, где автоматический рефакторинг отсутствует, уверенность работоспособности кода остаётся только на тестах). При функциональных же изменениях без тестов на работоспособность уже не обойтись. LCR>>Ты прав, и это не противоречит моим словам — в длительной перспективе тесты необходимы. Я же говорил о срочных проектах.
A>Понятие срочности очень растяжимое. Если "срочное" — это утилита, которая пишется два дня, выкидывается на использование и забывается, то конечно согласен, что тут тесты просто не успевают появиться (если конечно не используется методика TDD). Но если программа далее передаётся ещё и QA и затем наверняка возвращается для исправления ошибок, то, о каком же таком "срочном" проекте идёт речь?
2-3 месяца при функционале сравнимом скажем с оперой 5-й версии.
A>Еще, например я не пишу тестов для прототипов, потому как там действительно они только мешают быстро создавать эти самые прототипы.
+1, но о прототипах я даже не заикался (хотя я понимаю, что качество и наличие прототипирования очень сильно коррелируют).
A>P./S.: Напоследок ещё такое наблюдение: A>Отсутствие успешно отрабатывающих юнит-тестов говорит о халатности работы в команде, практически точно также как и коммит в репозиторий некомпилирующегося кода.
Аргх, опять догма. >:~(
A>C Уважением, Andir!
С уважением, LCR
borisman3,
B>Все. Написал бы больше, но нужно идти циферки складывать и денежки со счета на счет пересыпать... Большого Босса ублажать
Хотя я вот подумал, что как то звучит не хорошо (программисты предстают такими вечными мученниками и мальчиками на побегушках ). Можно ведь выразиться совсем иначе: "Большого Босса окучивать..." Здесь уже программисты предстают такими злыми гадами, издевающимися над бедной овечкой.
И то и другое конечно перегиб, истина как обычно по середине. (Где-то я натыкался на фразу, что коммерческое программирование — это сфера услуг, а услуги могут быть и высокоуровневыми, для IT в целом это так, имхо).
VD>2. Есть люди которые говорят как ты. Если высказаться более конкретно то это будет звучать так "Любые средства повышающие надежность кода хороши и полезны." При этом по хорошему надо добавлять "...если при этом они не создают проблем больше чем решают." LCR>>>Вдобавок, если юнит-тесты будут, то не будет (или будет в недостаточном количестве) чего-то другого. Как всегда, бесплатный сыр соблазнительно качается на пружинке... MR>>Не будет длительной отладки ? (шутка). На самом деле ты прав. Во всем важен баланс. Способсвует ли отсуствие или наличие ЮТ соблюдению баланса каждый отвечает сам. Ситуации они разные бывают.
Имелось ввиду именно это.
VD>Кстати, час Все же Фаулер довльно разумен и не столь радикален. Он продвигает многие средсвта повышающие качество кода. TDD только одно из них. Например, DSL-и он продвигает не хуже.
DSL имеют свою область применения. Точно так же как и TDD. Как я уже и говорил, для меня главное баланс. В той ситуации которую я описывал ЮТ показали себя с положительной стороны. Вопролен возможно что в другой команде или на другом проекте результат был бы другим. There is no silver bullet, как известно.
VD>Они используют юнит тесты для защиты, например, нетипизированных и опасных языков. В обсуждении тем связанных со статической типизации они постоянно принижают ее значения кивая на то что мол без юнит-тестов вообще не жить, а раз так то зачем тогда все эти проверки комиилятора. Все равно юнит-тесты все проверят.
Мне сложно говорить что-то относительно нетипизированных языков, поскольку дальше поверхностного изучения Scheme я не зашел ;( В целом я придерживаюсь мнения что использование типизированных и нетипизированных языков очень похоже на войну остроконечников и тупоконечников Свифта. Или споры о том чем удобнее кушать — китайскими палочками или вилкой. Человек пользуется тем, что ему удобнее. Одну и ту же задачу можно решить множеством способов, и не обязательно один из них заведомо лучше ИМХО... VD>Более того считаю что статическая типизация и безопасный язык даже более важны чем сами юнит тесты.
Опять же, все зависит от задачи имхо. Есть подозрение что существуют такие задачи которые с одинаковым успехом можно решить с статической типизацией и без нее. Вопрос в правильном применении инструмента. Лично я тоже склоняюсь к статической типизации, но это всего лишь вопрос предпочтения.
VD>Тесты проверяют динамику, а система типов статику.
+1
VD> Конечно юнит-тесты могут только помочь рефакторингу добавив контроля за ситуацией, но все же они не способны именно помочь и темболее автоматизировать рефакторин.
Собственно об автоматизации рефакторинга речь и не шла. Имелось ввиду именно контроль над ситуацией. Допустим при появлении студента в команде. VD> Те кто использует автоматизированный рефакторинг повседенвно так к нему привыкли, что даже незадумываются над тем, что их оппоненты не понимают этог, а стало быть оба лагеря недооценивают значимость автоматического рефакторинга.
Ну что тут можно сказать.. VS2005 рулит Но студия может обеспечить только синтаксическую и семантическую корректность. А когда при рефакторинге ломается логика, то получить максимально быстрый фидбек позволяют именно ЮТ имхо.
VD>Но даже если автоматический рефакторинг невозможен статическая типизация повзоляет существенно сократить объем работы и в особенности объем отладки, так как многие ошибки автоматически отлавливаются системой типов. При этом компилятор (особенно если он хороший) показывает места ошибок и содествует пониманию совершенной ошибки.
+1 Согласен на 100%. Но логические ошибки может отловить только человек. Ну или ЮТ написанные человеком. компилятор мало поможет если что-то поставит "+" вместо "-". Утрированно конечно, но тем не менее.
VD> Это намного лучше чем несработавший юнит-тест. Юнит тест только отлавивает ошибку. И не всегда из этого понятно в чем ошибка, и как ее отловить.
См. выше.
VD>Далее юнит-тесты все же сами по себе вызвают проблемы. а на самом деле ошибка находится в юнит-тесте и программист подтасовал результат кода под эту ошибку. Причем в рамках тество пробелем нет, но в реальном использовании они таки могут вылезти. Это уже наложенная ошибка. Так называемая — ошибка второго порядка.
Да, бывает и такое. Человек не машина..
VD>Ну и главное, юнет-тесты не отлавливают всех ошибко и не делают программу корректной. Они позволяют ввести дополнительный контроль. Это нужно четко понимать.
Равно как и любое тестирование. Никакое тестирование не отловит всех ошибок и не делают программу корректной. А хотелось бы Но Silver Bullet как обычно is out there.
VD>Есть разные задачи. Для одних юнит-тесты удобны. Для других неприменимы. Для теретих бессмысленны.
+1 VD> Тут нужны пакетные тесты содержащие много сложных сочетаний. Конечно и их можно назвать юнит-тестами, так как мы в итоге проверям результат пакетного теста с ожидаемым, но вот написать такой тест невозможно, да и не является он уже "Юнит". Он контролирует уже массу аспектов, а не какй-то один.
Лично я считаю (возможно ошибочно ) юнит тестом все, что может быполнить NUnit или его аналог
VD> что продукты лучше если их используют те кто пишет и если пользователи могут напрямую воздействовать на разработчиков.
dog food довольно распространненная практика. Но чем меньше багов получат конечные пользователи, тем лучше. По моему мнению юнит тесты позволяют снизить в какой-то мере количество багов в релизах. Не до нуля естественно..
VD>инструмент повышения качества кода. Не болше и не меньше.
Не совсем согласен. В примере который я приводил Lazy Cjow Rhrr ЮТ помогли сделать разработку быстрее. Но я повторюсь, возможно в других условиях результаты были бы другими.. Все та же пуля.. VD>Не надо низводить его до полной никчемности, но и не стоит делать из него религию и строить свою разработку исключительно отталкиваясь от них.
+1
minorlogic wrote: > Вот на эту мысль я и пытался навести , что тестировать наиболее удобно > маленькие отдельные модуле , а если сам тест встроен еще и в исполняемый > код , то это почти идеально. И разделять юнит тесты в некое отдельно > приложение не всегда разумно.
Ыыы... Ну вообще-то юнит-тесты — это как раз и есть наборы небольших
тестов, часто встраиваемых в сам код модуля (в Питоне, например).
Здравствуйте, Cyberax, Вы писали:
C>FDSC wrote: >> C>Пишем тест, который вызывает попадания во все ветки условий (их там >> C>совсем немного). >> Не понял, что проверяется и что от этого будет? Ведь я могу случайно (у >> меня такое действительно было) вместо < поставить >, и ЮТ уже ничем не >> поможет тогда. C>Для этого надо сравнивать результирующие данные с эталоном.
Ну, вот и получается, что я использую для этого комплексные тесты для всей системы, которые проверяют работу всей системы, а не её отдельных частей и что ЮТ тут не нужны совершенно.
>> У меня в алгоритме никаких веток, собственно нет. Там можно проверить >> только что вообще по всем узлам прошёл. Да и то будут ложные >> срабатывания, если граф несвязный. Для меня ложные срабатывания в ЮТ >> самая большая проблема была, когда я ими пытался пользоваться. C>Проблема с алгоритмической корректностью — это уже совсем другая история.
Алгорит у меня правильный, но я случайно поставил "<" вместо ">", мне нужно найти эту ошибку — она чисто кодировочная. Для некоторых алгоритмов это существенно, потому что не сразу заметно, хотя для крат. пути, конечно, сразу видно. Или, скажем, я забыл вызвать определённую функцию, которая иногда переставляет что-то местами, а иногда нет. Если я буду проверять код вручную на соответствие алгоритму — я её скорее всего довольно быстро найду, а если ЮТ, совершенно необязательно, если она появляется выборочно только для некоторых наборов. Поэт. лучше потратить время на ревизию, чем на написание ЮТ. А проверять всё комплексным тестом, возможно, автоматизированным.
C>Юнит-тесты нужны для проверки непосредственно правильности кода.
Ну и как я проверю правильность кода без проверки корректности алгоритма, реализующего метод Гаусса, например (простейший алгоритм, явно корректный). Меня там вообще на ЮТ достали ложные срабатывания, потому что я сделал автогенерацию неправильно. Я самого Гаусса написал быстрее раз в 5, чем правильные ЮТ для него. И, кстати, когда пришла пора использования, в моей реализации нашлась ошибка, которую ЮТ проглядели.
Здравствуйте, Mirrorer, Вы писали:
VD>> Тут нужны пакетные тесты содержащие много сложных сочетаний. Конечно и их можно назвать юнит-тестами, так как мы в итоге проверям результат пакетного теста с ожидаемым, но вот написать такой тест невозможно, да и не является он уже "Юнит". Он контролирует уже массу аспектов, а не какй-то один. M>Лично я считаю (возможно ошибочно ) юнит тестом все, что может быполнить NUnit или его аналог
ЮТ (в моём понимании), это то, что тестирует только некоторый конкретный небольшой модуль. Подразумевается при этом, что всё, что он использует, тестируется другими ЮТ или надёжно работает. ЮТ генерирует входные данные автоматически или по заданному набору, аналогично сверяет результат, по косвенным критериям правильности или по заданному набору правильных результатов.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Положа руку на сердце хотелось бы делать что-нибудь хотя бы приблизительно напоминающее (по надёжности) AXD 301 Но ресурсы малы и возможности не те...
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Желаю всем быстрых как молния и надёжных как бронепоезд программ, за которые заказчики с раздостью бы платили много $$$$$$! LCR>
Надеюсь, за это время никому не понадобиться программ быстрее молнии и надёжней бронепоезда , что, впрочем, маловероятно
FDSC wrote: > C>Для этого надо сравнивать результирующие данные с эталоном. > Ну, вот и получается, что я использую для этого комплексные тесты для > всей системы, которые проверяют работу всей системы, а не её отдельных > частей и что ЮТ тут не нужны совершенно.
Нет, тестируешь эталонный выход именно для алгоритма (ручками на простом
графе из нескольких узлов).
> C>Проблема с алгоритмической корректностью — это уже совсем другая история. > Алгорит у меня правильный, но я *случайно* поставил "<" вместо ">", мне > нужно найти эту ошибку — она чисто кодировочная.
Пишем тесты, которые покрывают все ветки алгоритма. Обычно ошибка в
ветке алгоритма приведет к неправильному результату.
Здравствуйте, borisman3, Вы писали:
B>Достоинства,
который для меня — недостатки B>1) Заставляют продумывать заранее, что нужно запрограммировать (test-first).
Но совершенно не в том ракурсе, который нужен: всё получается как-то угловато
B>2) Заставляют строить модульные системы.
Модульные системы заставляет строить сложность.
А ЮТ заставляют их разбивать на мелкие модули, которые часто даже выглядят не очень, потому что систему разбивали быстро и никто не позаботился об архитектуре мелких модулей.
B>3) Действительно улучшают качество выходного продукта.
Да, но как уже тут говорилось, есть много других способов улучшить качество продукта за теже ресурсы, и никто не докажет, что ЮТ тут лучше других. Хотя, согласен, улучшают
B>4) Создают приятное (ложное) ощущение, что проект работает верно.
Лично мне они создают нервотрёпку...
B>Недостатки B>1) Вводят в ступор (тут без теста бы сообразить, с какого вообще конца браться, а ты гришь test-first...) B>2) Требуют дополнительных усилий на их написание B>3) Стремятся сделать проект менее гибким, а именно: B> 3.1) Требуют времени на пожжержание дополнительного кода B> 3.2) Требуют времени на согласование изменений в коде и тестах
Согласен
B>4) Создают ложное (приятное) ощущение, что проект работает верно.
Точнее, создают ложное ощущение, что проект можно больше не тестировать
B>В моей практике очень часто возникают такие ситуации, когда изменения в коде влекут такие катастрофические изменения тестов, что я просто начисто вырезаю с мясом целые тест-сюиты, так как не вижу смысла их поддерживать в дальнейшем.
Потому что незаботились об архитектуре ЮТ [! тут об нормальной-то архитектуре позаботились бы...]
Здравствуйте, Cyberax, Вы писали:
C>FDSC wrote: >> C>Для этого надо сравнивать результирующие данные с эталоном. >> Ну, вот и получается, что я использую для этого комплексные тесты для >> всей системы, которые проверяют работу всей системы, а не её отдельных >> частей и что ЮТ тут не нужны совершенно. C>Нет, тестируешь эталонный выход именно для алгоритма (ручками на простом C>графе из нескольких узлов).
Ручками всё правильно получится. Я же уже сказал: при кодировании случайно допустил ошибку. Даже выделил ведь жирно, а вы убрали из цитирования.
>> C>Проблема с алгоритмической корректностью — это уже совсем другая история. >> Алгорит у меня правильный, но я *случайно* поставил "<" вместо ">", мне >> нужно найти эту ошибку — она чисто кодировочная. C>Пишем тесты, которые покрывают все ветки алгоритма. Обычно ошибка в C>ветке алгоритма приведет к неправильному результату.
Часто очень сложно понять, как сделать входные данные, что бы побывать во всех ветках и это требует напряжённой и сложной работы. Поэтому я и говорю: лучше комплекно программу проверить, а вместо ЮТ лишний раз пробежаться по коду глазами.
C>Контроль покрытия осуществляется специальными инструментами. Могу C>порекламировать мой Boost.Coverage Вот пример вывода: C>http://elewise.com/~cyberax/cov_test/tz_database_.._.._.._boost_lexical_cast.hpp_fl.html
Спасибо. Однако кроме контроля покрытия ещё нужны входные данные, которые это покрытие обеспечат. Честно скажу: в моих приложениях я сам часто разрабатываю или модифицирую стандартные алгоритмы, но вот придумать такие входные данные практически никогда не могу. Вот если бы ваш инструмент мог их выдумывать — цены бы ему не было.
LCR>>Положа руку на сердце хотелось бы делать что-нибудь хотя бы приблизительно напоминающее (по надёжности) AXD 301 Но ресурсы малы и возможности не те...
FDS>Что такое AXD 301? FDS>
Тут Lazy Cjow Rhrr сказал, что в отпуск уходит, так что я отвечу.
The AXD 301 is a new, general-purpose, high-performance ATM switch from
Ericsson that can be used in several positions in a network. In its initial
release, the AXD 301 is scaleable from 10 Gbit/s—in one subrack—up to
160 Gbit/s. The AXD 301 supports every service category defined for ATM,
including ABR. An advanced buffering mechanism allows services to be
mixed without compromising quality.
Designed for non-stop operation, the AXD 301 incorporates duplicate hardware
and software modularity, which enables individual modules to be
upgraded without disturbing traffic. The switching system, which supports
both ATM Forum and ITU-T signaling, is easily managed using an embedded
Web-based management system.
Основной функционал написан на Эрланге, с дополнительной функциональностью на С и Java.
... << RSDN@Home 1.2.0 alpha rev. 647>> ... <<Kenji Kawai — 10 Kugutsuuta kagirohi ha yomi ni mata muto>> ...
Здравствуйте, FDSC, Вы писали:
LCR>>Положа руку на сердце хотелось бы делать что-нибудь хотя бы приблизительно напоминающее (по надёжности) AXD 301 Но ресурсы малы и возможности не те...
FDS>Что такое AXD 301? FDS>
Здравствуйте, vvaizh, Вы писали:
LCR>>Да, спасибо, но! Вся разница со способом сравнения с эталонным выводом в том, что здесь тестовый вывод выдирается из БД и над ним производятся некие вычисления?
V>зачем производить вычисления? V>вот у тебя отработала некая часть системы.. V>что после неё должно измениться? V>как ты это проверяешь при ручной отладке? V>наверно запрос какой нибудь тестовый выполняешь? V>вот и тут также абсолютно.. V>ты почитай пример там всё просто описано.. V>если процесс регистрации пользователя, то должна добавиться запись в таблице пользователей V>её запросом и смотришь..
Я, например, когда система работает неправильно, частенько сажусь и смотрю код, а не начинаю сразу искать ошибку в отладчике. Особенно, если эта ошибка локализована.
LCR>>Как это облегчит рутинность создания юнит-тестов?
LCR>>Нам теперь нужно сформировать (1) эталонный вывод,
V>нам не нужно его "формировать" V>нам нужно : V>1. запустить один раз тест, V>2. проконтроллировать глазками что тест на выход выдал правильный результат V>3. банально объявить этот результат эталонным V>всё это выполняется буквально несколькими нажатиями клавиши/мышки
То есть для этого нам нужна уже готовая правильно работающая программа. Такие ЮТ могут найти ошибку только при изменении программы, но не при её первичной отладке. Надеюсь, это очевидно.
LCR>>И этот комплекс мер избавляет от рутины при написании ЮТ? V>не избавляет, но существенно уменьшает рутину V>сводя её почти до тех же трудозатрат, которые и так необходимы при обычной отладке..
Совершенно не сводит к трудозатратам обычной отладки, совершенно!
V>просто обычно при недостатке времени тестируются считанные еденицы вариантов использования системы "в целом", V>не заморачиваясь на отдельных частях..
Ну, считанные единицы, это ты загнул: уж все варианты тестируются, и некоторые не по одному разу. И, заметь, если есть ошибка, то она вылетит сразу на одном тесте для всех модулей — т.е. объём тестов меньше. Другой вопрос, что в код часто то же вставляются проверки корректности, которые позволяют быстро локализовать ошибку.
Здравствуйте, FDSC, Вы писали:
LCR>>>Да, спасибо, но! Вся разница со способом сравнения с эталонным выводом в том, что здесь тестовый вывод выдирается из БД и над ним производятся некие вычисления?
V>>зачем производить вычисления? V>>вот у тебя отработала некая часть системы.. V>>что после неё должно измениться? V>>как ты это проверяешь при ручной отладке? V>>наверно запрос какой нибудь тестовый выполняешь? V>>вот и тут также абсолютно.. V>>ты почитай пример там всё просто описано.. V>>если процесс регистрации пользователя, то должна добавиться запись в таблице пользователей V>>её запросом и смотришь.. FDS>Я, например, когда система работает неправильно, частенько сажусь и смотрю код, а не начинаю сразу искать ошибку в отладчике. Особенно, если эта ошибка локализована.
а если не локализована?
тесты и призваны помочь быстро локализовать ошибки
LCR>>>Как это облегчит рутинность создания юнит-тестов? LCR>>>Нам теперь нужно сформировать (1) эталонный вывод, V>>нам не нужно его "формировать" V>>нам нужно : V>>1. запустить один раз тест, V>>2. проконтроллировать глазками что тест на выход выдал правильный результат V>>3. банально объявить этот результат эталонным V>>всё это выполняется буквально несколькими нажатиями клавиши/мышки FDS>То есть для этого нам нужна уже готовая правильно работающая программа. Такие ЮТ могут найти ошибку только при изменении программы, но не при её первичной отладке. Надеюсь, это очевидно.
ну всё же просто..
начинают же пробно запускать с первой строчки "hello world".. это уже правильная программа..
и вывод с неё же проверять..
а потом добавляют что то..
при этом вывод который нужно проверять всё разрастается..
тут то средство и помогает, так как показывает только как по сравнению с предыдущим эталоном вывод изменился..
не нужно тщательно глазами искать/вычитывать..
как говорится
1. палка
— проверил, записал результат как эталонный
2. палка
— проверил, переписал эталон
3. огуречик
— проверил, переписал эталон
4. вот и вышел человечек
— получили готовый тест и результат для заказчика
т.е. и писать помогает и тесты регрессионные сразу готовы
LCR>>>И этот комплекс мер избавляет от рутины при написании ЮТ? V>>не избавляет, но существенно уменьшает рутину V>>сводя её почти до тех же трудозатрат, которые и так необходимы при обычной отладке..
FDS>Совершенно не сводит к трудозатратам обычной отладки, совершенно!
ну.. к этому нужно стремиться..
т.е. простая мысль, человек при отладке выполняет над программой какие то действия,
запускает её с какими то данными
что то в ней делает..
средство должно максимально просто использовать эту информацию..
например пишет человек что то в program argument сразу в отладчике..
а почему там только одна строка?
а почему не несколько чтобы можно было выбирать, или сразу даже подрят в разных вариантах запускать?
и т.п.
Здравствуйте, FDSC, Вы писали:
LCR>>Положа руку на сердце хотелось бы делать что-нибудь хотя бы приблизительно напоминающее (по надёжности) AXD 301 Но ресурсы малы и возможности не те...
FDS>Что такое AXD 301? FDS>
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Твоя мысль согласуется с теми же Фаулерами, Беками и прочими: они говорят, чтобы мы вообще обложились тестами по самую макушку: юнит-, интеграционные, регрессионные, стресс-тесты, причём задействована должна быть каждая строчка в программе. Тогда можно с некоторой уверенностью сказать, что программа работает... Но всё это очень трудоёмко
"Атлас" тоже думал что трудоемко. Страна чуть без алкоголя не осталась.
Здравствуйте, borisman3, Вы писали:
B>Да и вообще. Вы сами уже ответили на все вопросы, когда сказали что worse is better. Мы будем делать то, что надо [клиенту], а того, что не надо [клиенту] мы делать не будем. А ему часто по барабану все эти тесты, красивая архитектура, запредельное качество. Клиент у нас с Вами — не министерство обороны с встроенными системами на подлодках, клиент у нас простодушный Большой Босс Владеющий Банками Заводами Пароходами, делайте то что ЕМУ важно, а на то, что программа вываливается в корку, когда пытаешься на сааамый удаленный пункт меню нажать он (клиент) даже внимания не обратит. А если обратит, честно признаем, что она (программа) не идальна, у всех свои недостатки. Клиент поймет.
Это смотря кто клиент и кто твоя фирма. Если фирма работает с откатами, то наверно поймет. А ежели без откатов, то тут хочешь или не хочешь нужно держать качество программы константным. К тому же, внутри фирмы человек(группа) которая делает меньше ошибок и быстрее тестируется значительно более высоко ценится.
Здравствуйте, FDSC, Вы писали:
FDS>ЮТ (в моём понимании), это то, что тестирует только некоторый конкретный небольшой модуль. Подразумевается при этом, что всё, что он использует, тестируется другими ЮТ или надёжно работает. ЮТ генерирует входные данные автоматически или по заданному набору, аналогично сверяет результат, по косвенным критериям правильности или по заданному набору правильных результатов.
А если необходимо проверить взаимодейтствие нескольких модулей, будет ли это юнит тестом или нет ? Или допустим некоторый сценарий использования. Что мешает такие вещи запихнуть в юнит тест? Если хочется иметь уверенность что основные сценарии не ломаются при рефакторинге\оптимизации ?
Здравствуйте, Mirrorer, Вы писали:
M>Здравствуйте, FDSC, Вы писали:
FDS>>ЮТ (в моём понимании), это то, что тестирует только некоторый конкретный небольшой модуль. Подразумевается при этом, что всё, что он использует, тестируется другими ЮТ или надёжно работает. ЮТ генерирует входные данные автоматически или по заданному набору, аналогично сверяет результат, по косвенным критериям правильности или по заданному набору правильных результатов.
M>А если необходимо проверить взаимодейтствие нескольких модулей, будет ли это юнит тестом или нет ?
1. Модули взаимодействуют в другом модуле — это ЮТ для этого модуля.
2. Модули просто взаимодействуют — это уже превышение полномочий , это не ЮТ. Это уже просто автоматизированный тест. Другой вопрос, если эти модули можно как-то выделить в блок, который предстаёт другим подпрограммам как единое целое — это юнит тест. Т.е. многое зависит от архитектуры.
Теоретическое свойство ЮТ, которое есть необходимое условие для того, что бы тест признать Юнит Тестом: если при запуске всех ЮТ программы, которые покрывают основную её функциюнальность, выдаётся ошибка только в одном ЮТ, то ошибка с очень высокой вероятностью находится в той программной единице, которую проверяет данный ЮТ.
Поэтому он, собственно, и называется ЮТ.
M> Или допустим некоторый сценарий использования. Что мешает такие вещи запихнуть в юнит тест?
Тест для сценария использования некоторой библиотеки есть ЮТ для её интерфейса и не есть ЮТ для неё самой, если только главная её логика не зашита в одной небольшой программной единице.
Под программной единицей понимается некий программный код, реализующий одну логически целостную функцию, например, модуль для решения СЛАУ есть программная единица. Модуль (библиотека) для решения краевой задачи некоторым методом есть программная единица, использующая модули решения СЛАУ и численного интегрирования методом Рунге-Кутты.
Если, скажем, библиотека содержит две функции: решения краевой задачи и решения жёсткой (линейной) краевой задачи, то она, возможно, состоит из двух программных единиц, которые требуют ЮТ. Т.е. проверка каждой из 2-х функций будет ЮТ. Если же эта библиотека содержит в себе непротестированные единицу, например, для решения СЛАУ, то это будет уже комплексный тест для нескольких программных единиц.
M> Если хочется иметь уверенность что основные сценарии не ломаются при рефакторинге\оптимизации ?
То же комплексный тест, если этот сценарий не использует один программный модуль, а программный модуль использует только протестированные другие программные модули.
Здравствуйте, vvaizh, Вы писали:
V>Здравствуйте, FDSC, Вы писали:
LCR>>>>Да, спасибо, но! Вся разница со способом сравнения с эталонным выводом в том, что здесь тестовый вывод выдирается из БД и над ним производятся некие вычисления?
V>>>зачем производить вычисления? V>>>вот у тебя отработала некая часть системы.. V>>>что после неё должно измениться? V>>>как ты это проверяешь при ручной отладке? V>>>наверно запрос какой нибудь тестовый выполняешь? V>>>вот и тут также абсолютно.. V>>>ты почитай пример там всё просто описано.. V>>>если процесс регистрации пользователя, то должна добавиться запись в таблице пользователей V>>>её запросом и смотришь.. FDS>>Я, например, когда система работает неправильно, частенько сажусь и смотрю код, а не начинаю сразу искать ошибку в отладчике. Особенно, если эта ошибка локализована.
V>а если не локализована? V>тесты и призваны помочь быстро локализовать ошибки
Моё личное мнение: тесты призваны ошибки найти. Никогда в жизни не видел тестов, которые ошибки локализуют: если только по случайности. Другой вопрос, ЮТ действительно, фактически локализуют ошибки, но это можно сделать быстро и без них. Если ЮТ способен локализовать ошибку, то её способен локализовать и программист, причём довольно быстро.
LCR>>>>Как это облегчит рутинность создания юнит-тестов? LCR>>>>Нам теперь нужно сформировать (1) эталонный вывод, V>>>нам не нужно его "формировать" V>>>нам нужно : V>>>1. запустить один раз тест, V>>>2. проконтроллировать глазками что тест на выход выдал правильный результат V>>>3. банально объявить этот результат эталонным V>>>всё это выполняется буквально несколькими нажатиями клавиши/мышки
FDS>>То есть для этого нам нужна уже готовая правильно работающая программа. Такие ЮТ могут найти ошибку только при изменении программы, но не при её первичной отладке. Надеюсь, это очевидно.
V>ну всё же просто.. V>начинают же пробно запускать с первой строчки "hello world".. это уже правильная программа.. V>и вывод с неё же проверять.. V>а потом добавляют что то.. V>при этом вывод который нужно проверять всё разрастается.. V>тут то средство и помогает, так как показывает только как по сравнению с предыдущим эталоном вывод изменился.. V>не нужно тщательно глазами искать/вычитывать..
V>как говорится V>1. палка V> — проверил, записал результат как эталонный V>2. палка V> — проверил, переписал эталон V>3. огуречик V> — проверил, переписал эталон
V>4. вот и вышел человечек V> — получили готовый тест и результат для заказчика
V>т.е. и писать помогает и тесты регрессионные сразу готовы
1. Даже если это ЮТ. После первого запуска программы мы сделали ЮТ на выдачу "Hello world", после второго, на следующую строку и т.д. Это значит, что всё равно весь вывод, который был сделан, первоначально протестировал программист. Он протестировал строку Hello world — сказал что правильно, написал ЮТ. Протестировал вторую строку — сказал что правильно, написал ЮТ. Дальше ему их тестировать естественно не надо.
Дак вот, из этого следует, что даже если справедлив ваш простой случай, когда результат выдач при разработке не меняется, всё равно первичное тестирование каждой новой функции проводится без использования ЮТ. ЮТ используется только при добавлении.
По другому, более корректно. Протестировали первый написанный модуль вручную, написали к нему ЮТ, ПОСЛЕ ручной проверки и получения эталона.
Следующий модуль мы то же сначала тестируем вручную (если делать, как вы говорите), а потом уже пишем для него ЮТ, естественно, ЮТ для первого модуля никуда не деваются, а помагают нам работать, но всё равно первичное тестирование обязательно.
2. ЮТ, как средство указанного вами контроля за изменениями может потребовать изменения, так как, скажем, вместо "hellow world" в нашей программе через некоторе время потребуется выводить "hello Petia". И этот ЮТ полетит на свалку. Следующий ЮТ, опят же, может быть написан только после того, как программист проверит вручную правильность выдачи hello Petia и исправит или напишет новый ЮТ.
3. Это уже не ЮТ. ЮТ тестируют конкретный программный модуль, класс.
Всё остальное — это просто автоматизированный тест.
Я то же иногда делаю полуавтоматические тесты, которые проверяют программный вывод, но они проверяют сразу всю программу, от начала до конца: загружают исходные данные, как это делает в начале работы пользователь, запускают некоторый цикл расчёта, сверяют результат с эталоном, который был получен и проверен программистом. Я бы это назвал Комплесным Тестом, так как 1. он не тестирует отдельный модуль, а тестирует всё программу, 2. в отличие от ЮТ он принципиально не может указать место ошибки — конкретный модуль, он может указать только наличие ошибки.
LCR>>>>И этот комплекс мер избавляет от рутины при написании ЮТ? V>>>не избавляет, но существенно уменьшает рутину V>>>сводя её почти до тех же трудозатрат, которые и так необходимы при обычной отладке..
FDS>>Совершенно не сводит к трудозатратам обычной отладки, совершенно!
V>ну.. к этому нужно стремиться.. V>т.е. простая мысль, человек при отладке выполняет над программой какие то действия, V>запускает её с какими то данными V>что то в ней делает..
V>средство должно максимально просто использовать эту информацию...
V>например пишет человек что то в program argument сразу в отладчике.. V>а почему там только одна строка? V>а почему не несколько чтобы можно было выбирать, или сразу даже подрят в разных вариантах запускать? V>и т.п.
Это уже не к ЮТ относится.
При ЮТ можно только довольно быстро и просто (в некоторых случаях) локализовать ошибку до уровня конкретного модуля. Далее всё равно требуется отладка, что бы локализовать ошибку до функции и до строки или группы строк в функции. Затем программисту всё равно нужно смотреть код, разбираться что он сделал неправильно и т.д. Т.е. практически полный цикл отладки и фиксации ошибок. Причём, при правильных проверках непосредственно внутри программы, которые, конечно, то же можно рассматривать как своеобразный ЮТ (но я предпочитаю этого не делать, так как ЮТ запускается при тестировании, а не при работе с программой) этап локализации то же значительно сокращается, сводя выгоду от ЮТ на нет. Другой вопрос, что при внесении изменений всё равно нужно сразу же запускать ЮТ или комплексное тестирование.
Здравствуйте, FDSC, Вы писали:
FDS>Другой вопрос, что при внесении изменений всё равно нужно сразу же запускать ЮТ или комплексное тестирование.
1. Время. Комплексное тестирование работает заметно дольше ЮТ.
2. Что касается пользы от ЮТ. У нас (j2ee) при разработке ЮТ валятся часто, то там то сям (привет статической типизации). До введения ЮТ часто были ситуации, что народ просто боялся обновлятся из VCS. Потому, что фиг потом поймёш это ты всё поломал, или кто другой. Потом всё это с огромным гимором мержилось. В общем, ЮТ+CruiseControl это есть хорошо.
3. Что касается тестеров как замены ЮТ: нужно уважать и их труд — зачем им отдавать приложение с явными ошибками? Тем более, что отдать им и не получится — по плану тестирования они перейдут к этому продукту через пару месяцев.
4. Применение ЮТ не отменяет тестирования людьми.
5. Помощь в разработке: я не умею пользоваться листком бумаги для программирования. Сел, пол часа-час подумал, пару линий накалякал, создал в голове крупную модель. А код на бумажке писать — увы. Тут ЮТ позволяют сосредоточится именно на том, что собрался делать, потому что пока пишеш ЮТ ты уже используеш свой класс. И тут уже могут вылазить косяки дизайна.
6. Да, множество трудностей происходит из-за факта, что тесты требуют понимания того, какой будет конечный результат. А без тестов код можно колбасить просто так, время от времени посматривая что же он на самом деле делает. И когда в голове сработает мысленный "будильник Кашпировского" значит мы допрограмили до нужного результата. Кстати, понимание какой же именно результат нужный, даже в этот момент может и не прийти, просто появляется уверенность, что ты всё сделал правильно. Так вот, не вижу ничего плохого в попытке избавится от такой правктики. И коль скоро в этом мне помогают тесты — я им только рад.
Здравствуйте, FDSC, Вы писали:
FDS>Моё личное мнение: тесты призваны ошибки найти. Никогда в жизни не видел тестов, которые ошибки локализуют: если только по случайности.
Поздравляю, вы плаваете в определениях.
Юнит-тесты как раз по определению должны локализовать ошибки
Т.е. каждый тест связан по идее с небольшим юнит-ом (блоком) программы,
который блок он и тестирует.. соответственно если упал тест, это автоматически
как бы по идее указывает в каком блоке (юните) ошибка..
в этом кстати отличие от функционального теста, который просто говорит что программа не работает
FDS>Другой вопрос, ЮТ действительно, фактически локализуют ошибки, но это можно сделать быстро и без них.
скорее наоборот.. они локализуют ошибки по определению, но не всегда фактически..
FDS>Если ЮТ способен локализовать ошибку, то её способен локализовать и программист, причём довольно быстро.
да никто не спорит..
просто он в сложных случаях должен восстанавливать условия при которых возникает ошибка..
а юнит тест как раз и есть автоматизация восстановления таких критических условий..
V>>т.е. и писать помогает и тесты регрессионные сразу готовы
FDS>1. Даже если это ЮТ. После первого запуска программы мы сделали ЮТ на выдачу "Hello world", после второго, на следующую строку и т.д. Это значит, что всё равно весь вывод, который был сделан, первоначально протестировал программист. Он протестировал строку Hello world — сказал что правильно, написал ЮТ. Протестировал вторую строку — сказал что правильно, написал ЮТ. Дальше ему их тестировать естественно не надо.
ничего подобного..
он просто один раз написал тест на весь вывод, и много раз ползуется одним и тем же тестом
просто результат теста всё время разный
но тест один и тот же
FDS>Дак вот, из этого следует, что даже если справедлив ваш простой случай, когда результат выдач при разработке не меняется, всё равно первичное тестирование каждой новой функции проводится без использования ЮТ. ЮТ используется только при добавлении.
ну как сказать..
всё равно тестирование происходит на определённых первоначальных условиях..
вот автоматизация задания этих условий уже есть некий тест.. так сказать предтеча..
нужно же залить тестовые данные
заполнить допустим какие то параметры запроса и т.п.
и мы либо каждый раз это ручками делаем, либо раз и навсегда автоматизируем..
FDS>По другому, более корректно. Протестировали первый написанный модуль вручную, написали к нему ЮТ, ПОСЛЕ ручной проверки и получения эталона. FDS>Следующий модуль мы то же сначала тестируем вручную (если делать, как вы говорите), а потом уже пишем для него ЮТ, естественно, ЮТ для первого модуля никуда не деваются, а помагают нам работать, но всё равно первичное тестирование обязательно.
ну почти так, кроме того, что я все же не являюсь сторонником чисто ЮТ, а считаю что ЮТ должно плавно проистекать из функционально-приёмочного тестирования (всё равно автоматическиого)
при определённых условиях любая пара тестов из трёх могут совпадать..
т.е. разница довольно тонкая..
несмотря на это больше всего шума и PR а вокруг unit-тестов
FDS>2. ЮТ, как средство указанного вами контроля за изменениями может потребовать изменения, так как, скажем, вместо "hellow world" в нашей программе через некоторе время потребуется выводить "hello Petia". И этот ЮТ полетит на свалку.
мой — не полетит
мой подход (со сваливанием результатов файл) позволяет быстро проконтроллировать что поменялось в эталонах
и одним действием актуализировать все эталоны по новым результатам
FDS>Следующий ЮТ, опят же, может быть написан только после того, как программист проверит вручную правильность выдачи hello Petia и исправит или напишет новый ЮТ.
зачем новый ЮТ то ?
FDS>3. Это уже не ЮТ. ЮТ тестируют конкретный программный модуль, класс. FDS>Всё остальное — это просто автоматизированный тест.
в общем да, хотя
они могут и совпадать
FDS>Я то же иногда делаю полуавтоматические тесты, которые проверяют программный вывод, но они проверяют сразу всю программу, от начала до конца: загружают исходные данные, как это делает в начале работы пользователь, запускают некоторый цикл расчёта, сверяют результат с эталоном, который был получен и проверен программистом. Я бы это назвал Комплесным Тестом, так как 1. он не тестирует отдельный модуль, а тестирует всё программу, 2. в отличие от ЮТ он принципиально не может указать место ошибки — конкретный модуль, он может указать только наличие ошибки.
всё так, кроме того что:
1. можно подбирать тестовые данные таким образом чтобы тестировать именно конкретный модуль
2. можно на каждый модуль писать отдельный запускаемый файл с консольно-текстовым интерфейсом для его тестирования
3. можно сами юнит-тесты реализовать так, чтобы вместо ассертов был вывод в файл
в общем именно такой подход я и пытаюсь продвинуть своей тулзой
V>>например пишет человек что то в program argument сразу в отладчике.. V>>а почему там только одна строка? V>>а почему не несколько чтобы можно было выбирать, или сразу даже подрят в разных вариантах запускать? V>>и т.п.
FDS>Это уже не к ЮТ относится.
ну относится/не относится уже дело десятое
главное чтобы работать было удобно
а как это называется, и насколько увязано пофиг
FDS>2. Модули просто взаимодействуют — это уже превышение полномочий , это не ЮТ. Это уже просто автоматизированный тест.<CUT>если при запуске всех ЮТ программы, которые покрывают основную её функциюнальность, выдаётся ошибка только в одном ЮТ, то ошибка с очень высокой вероятностью находится в той программной единице, которую проверяет данный ЮТ.
Именно это меня и заставило расширить мое определение юнит теста. Сложно провести границу между ЮТ который тестирует один модуль(классический вариант) и комплексным автоматизированным тестом который выполняется с помощью какого-нибудь xUnit. Строго говоря комплексный тест не будет являться ЮТ, тут я с тобой согласен, но как его тогда называть ? И какие есть утилиты позволяющие проводить автоматизированное тестирование без отрыва от производства? По уровню удобства для меня xUnit на первом месте.. Утилиты для ЮТ позволяют тестировать гораздо больше чем просто контракты одного модуля. И это позволяет обнаружить некоторые ошибки еще до отправки их тестеру. А при обнаружении бага тестером можно багу оформить как ЮТ(комплексный тест ?) и потом быть абсолютно уверенным что тот самый баг уже не всплывает. (Естественно если баг можно смоделировать программно )
FDS> Т.е. проверка каждой из 2-х функций будет ЮТ. Если же эта библиотека содержит в себе непротестированные единицу, например, для решения СЛАУ, то это будет уже комплексный тест для нескольких программных единиц.
Просто уточнение. Комплексный тест зашитый в TestSuite является ЮТ или нет ? Я почему-то считал что да. Но как я писал выше возможно это мнение ошибочно. Ни в одной книге по ЮТ не видел разделения на комплексные и юнит тесты. Отсюда и некоторый бардак в понятиях...
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, FDSC, Вы писали:
FDS>>Другой вопрос, что при внесении изменений всё равно нужно сразу же запускать ЮТ или комплексное тестирование.
ANS>1. Время. Комплексное тестирование работает заметно дольше ЮТ.
Это не так. Допустим, на каждый модуль у вас 10 ЮТ тестов. У меня 10 КТ тестов на всю программу. У вас каждый модуль отрабатывает в ЮТ по 10 раз и у меня столько же.
Другой вопрос, если вы поменяли один модуль и только его оттестировали — то да, вы правы, но лично для меня это никогда не было критичным. А вот то, что после изменения одного модуля всё равно нужно провести КТ, на всякий случай, это для меня непреложная истина. Так что получается, что я всё равно буду проводить КТ и машинное время всё равно будет потрачено.
ANS>2. Что касается пользы от ЮТ. У нас (j2ee) при разработке ЮТ валятся часто, то там то сям (привет статической типизации). До введения ЮТ часто были ситуации, что народ просто боялся обновлятся из VCS. Потому, что фиг потом поймёш это ты всё поломал, или кто другой. Потом всё это с огромным гимором мержилось. В общем, ЮТ+CruiseControl это есть хорошо.
Бранчи надо делать
К сожалению, ваш и мой опыт сильно расходятся. К тому же, что мешает вместо ЮТ запустить КТ на локальной копии не очень то понятно. В этом случае ЮТ хорош, если программисту недоступен весь проект целиком. (да и собирать его лишний раз..., впрочем на Яве, я так понимаю, это не имеет значения)
ANS>3. Что касается тестеров как замены ЮТ: нужно уважать и их труд — зачем им отдавать приложение с явными ошибками? Тем более, что отдать им и не получится — по плану тестирования они перейдут к этому продукту через пару месяцев.
Это была шутка. Вообще я за автоматизированный или ручной КТ. ЮТ для меня слишком трудоёмки: я вместо них анализ кода провожу (и, кстати, часто нахожу ошибки).
ANS>4. Применение ЮТ не отменяет тестирования людьми.
Но отнимает дополнительное время.
ANS>5. Помощь в разработке: я не умею пользоваться листком бумаги для программирования. Сел, пол часа-час подумал, пару линий накалякал, создал в голове крупную модель. А код на бумажке писать — увы. Тут ЮТ позволяют сосредоточится именно на том, что собрался делать, потому что пока пишеш ЮТ ты уже используеш свой класс. И тут уже могут вылазить косяки дизайна.
Согласен с вашим опытом, но к моему он не применим. Мне ЮТ мешают сосредоточится и на архитектуре, и кодировании. А ошибки проектирования я выявляю просто используя принцип: приложение всегда должно работать, даже если оно работает совсем не так, как конечная версия. И дополнительного кодирования тут очень мало, по сравнению с ЮТ.
ANS>6. Да, множество трудностей происходит из-за факта, что тесты требуют понимания того, какой будет конечный результат. А без тестов код можно колбасить просто так, время от времени посматривая что же он на самом деле делает. И когда в голове сработает мысленный "будильник Кашпировского" значит мы допрограмили до нужного результата. Кстати, понимание какой же именно результат нужный, даже в этот момент может и не прийти, просто появляется уверенность, что ты всё сделал правильно. Так вот, не вижу ничего плохого в попытке избавится от такой правктики. И коль скоро в этом мне помогают тесты — я им только рад.
Ну насколько у нас большая разница в подходах к разработке ПО! Без тестов я понимаю что делает код, с тестами — считаю что работают правильно отдельные модули, значит и в целом всё правильно . Поэтому мне ЮТ как раз мешают понимать, что делает программа (да на это уже и времени не остаётся)
Здравствуйте, Mirrorer, Вы писали:
FDS>>2. Модули просто взаимодействуют — это уже превышение полномочий , это не ЮТ. Это уже просто автоматизированный тест.<CUT>если при запуске всех ЮТ программы, которые покрывают основную её функциюнальность, выдаётся ошибка только в одном ЮТ, то ошибка с очень высокой вероятностью находится в той программной единице, которую проверяет данный ЮТ.
M>Именно это меня и заставило расширить мое определение юнит теста. Сложно провести границу между ЮТ который тестирует один модуль(классический вариант) и комплексным автоматизированным тестом который выполняется с помощью какого-нибудь xUnit. Строго говоря комплексный тест не будет являться ЮТ, тут я с тобой согласен, но как его тогда называть ? И какие есть утилиты позволяющие проводить автоматизированное тестирование без отрыва от производства? По уровню удобства для меня xUnit на первом месте.. Утилиты для ЮТ позволяют тестировать гораздо больше чем просто контракты одного модуля. И это позволяет обнаружить некоторые ошибки еще до отправки их тестеру. А при обнаружении бага тестером можно багу оформить как ЮТ(комплексный тест ?) и потом быть абсолютно уверенным что тот самый баг уже не всплывает. (Естественно если баг можно смоделировать программно )
Речь идёт просто о разнице в терминологии. Для кого-то это не важно. Для меня важно: ЮТ я практически никогда не пользуюсь, а под КТ я всю разработку подгоняю (если нужно, к счастью, пока что я программирую один или занимаюсь отдельным независимым модулем).
FDS>> Т.е. проверка каждой из 2-х функций будет ЮТ. Если же эта библиотека содержит в себе непротестированные единицу, например, для решения СЛАУ, то это будет уже комплексный тест для нескольких программных единиц.
M>Просто уточнение. Комплексный тест зашитый в TestSuite является ЮТ или нет ? Я почему-то считал что да. Но как я писал выше возможно это мнение ошибочно. Ни в одной книге по ЮТ не видел разделения на комплексные и юнит тесты. Отсюда и некоторый бардак в понятиях...
Собственно КТ — это я тут сказал, на самом деле ведь это обычные не юнит тесты, их просто называют "процессом тестирования". Всем понятно что такое обычный тест и его прото никак не называют и не описывают . Возможно, моё понятие ЮТ вообще безграмотно и в корне неверно, не знаю...
M>Комплексный тест зашитый в TestSuite является ЮТ или нет ?
Он же комплексный... Вообще, насколько я понимаю, пакеты для тестирования (типа NUnit) собственно позволяют писать с точки зрения теории не-ЮТ точно так же как и ЮТ. Тем более, если посмотреть на обсуждение выше, то если для одного программного модуля написан ЮТ, но модуль пользуется другим непроверенным программным модулем, то это уже вроде как получается КТ... то есть они различимы только программистом, но не средствами тестирования.
Т.е. всё зависит от желания разработчика теста , хотя если по всей строгости подходить, то КТ не может быть ЮТ. Но ведь в реальности никогда не пользуются некоторой методикой по всей строгости: всегда применяют комбинации и модификации под себя.
Здравствуйте, vvaizh, Вы писали:
V>Здравствуйте, FDSC, Вы писали:
FDS>>Моё личное мнение: тесты призваны ошибки найти. Никогда в жизни не видел тестов, которые ошибки локализуют: если только по случайности.
V>Поздравляю, вы плаваете в определениях.
V>Юнит-тесты как раз по определению должны локализовать ошибки V>Т.е. каждый тест связан по идее с небольшим юнит-ом (блоком) программы, V>который блок он и тестирует.. соответственно если упал тест, это автоматически V>как бы по идее указывает в каком блоке (юните) ошибка..
Поздравляю и вас: вы меня невнимательно читаете. Привожу полную цитату (вы убрали кусок): FDS>>Моё личное мнение: тесты призваны ошибки найти. Никогда в жизни не видел тестов, которые ошибки локализуют: если только по случайности. Другой вопрос, ЮТ действительно, фактически локализуют ошибки, но это можно сделать быстро и без них. Если ЮТ способен локализовать ошибку, то её способен локализовать и программист, причём довольно быстро.
Вы можете так же посмотреть в этой теме топик "Что такое ЮТ" — там я привёл свойство, которым по моему мнению, обладают ЮТ:
FDS>>если при запуске всех ЮТ программы, которые покрывают основную её функциюнальность, выдаётся ошибка только в одном ЮТ, то ошибка с очень высокой вероятностью находится в той программной единице, которую проверяет данный ЮТ.
V>в этом кстати отличие от функционального теста, который просто говорит что программа не работает
Да, я и написал выше "...не видел тестов, которые...", именно "тестов", а не ЮТ. Читайте повнимательнее
Так что в определениях я не плаваю. Думаю вопрос закрыт.
FDS>>Другой вопрос, ЮТ действительно, фактически локализуют ошибки, но это можно сделать быстро и без них.
V>скорее наоборот.. они локализуют ошибки по определению, но не всегда фактически..
По определению они ничего не локализуют — они тестируют Из моих высказываний вы могли понять что я полностью разделяю эту точку зрения. В частности это можно понять из приведённой ниже цитаты ("Если ЮТ способен локализовать ошибку", т.е. есть ситуации, когда ЮТ не может этого сделать).
FDS>>Если ЮТ способен локализовать ошибку, то её способен локализовать и программист, причём довольно быстро.
V>да никто не спорит.. V>просто он в сложных случаях должен восстанавливать условия при которых возникает ошибка.. V>а юнит тест как раз и есть автоматизация восстановления таких критических условий..
Любой тест, который воспроизводит некоторую ситуацию способен вызвать ошибку, соответствующую этой ситуации. Это не есть уникальное свойство ЮТ, это есть общее свойство тестов, которые работают по некоторым статичным входным данным.
V>>>т.е. и писать помогает и тесты регрессионные сразу готовы
FDS>>1. Даже если это ЮТ. После первого запуска программы мы сделали ЮТ на выдачу "Hello world", после второго, на следующую строку и т.д. Это значит, что всё равно весь вывод, который был сделан, первоначально протестировал программист. Он протестировал строку Hello world — сказал что правильно, написал ЮТ. Протестировал вторую строку — сказал что правильно, написал ЮТ. Дальше ему их тестировать естественно не надо.
V>ничего подобного.. V>он просто один раз написал тест на весь вывод, и много раз ползуется одним и тем же тестом V>просто результат теста всё время разный V>но тест один и тот же
Вы противоречите сами себе: раньше вы говорили, что результат будет получен после правильной отработки, теперь вы говорите, что тест может работать без этого результата (т.к. написали что "просто результат теста всё время разный"). Естественно, если тест проверяет результат по косвенным критериям, а не сравнением, то это возможно. Но тогда у него есть другой минус: его очень тяжело писать, иногда невозможно.
Вы уж определитесь о каком виде тестов мы говорим.
FDS>>Дак вот, из этого следует, что даже если справедлив ваш простой случай, когда результат выдач при разработке не меняется, всё равно первичное тестирование каждой новой функции проводится без использования ЮТ. ЮТ используется только при добавлении.
V>ну как сказать.. V>всё равно тестирование происходит на определённых первоначальных условиях.. V>вот автоматизация задания этих условий уже есть некий тест.. так сказать предтеча.. V>нужно же залить тестовые данные V>заполнить допустим какие то параметры запроса и т.п.
V>и мы либо каждый раз это ручками делаем, либо раз и навсегда автоматизируем..
Если вы согласны с тем, что это нужно сделать целый один раз, т.е. получить правильную часть программы сначала без ЮТ или вручную получить правильный результат, то да. Мы и говорим, что сначала нам нужно тестировать всё в ручную, а потом использовать ЮТ, ПОСЛЕ ручного тестирования, фактически, как регрессионный тест. Данный пункт и призван вам показать этот недостаток вами же предложенного варианта со статическими входными данными: программа должна быть написана сначала без ЮТ, с помощью ручного тестирования.
Вы то ли хотите сбить меня с линии спора, то ли сами её потеряли, я удивлён.
FDS>>По другому, более корректно. Протестировали первый написанный модуль вручную, написали к нему ЮТ, ПОСЛЕ ручной проверки и получения эталона. FDS>>Следующий модуль мы то же сначала тестируем вручную (если делать, как вы говорите), а потом уже пишем для него ЮТ, естественно, ЮТ для первого модуля никуда не деваются, а помагают нам работать, но всё равно первичное тестирование обязательно.
V>ну почти так, кроме того, что я все же не являюсь сторонником чисто ЮТ, а считаю что ЮТ должно плавно проистекать из функционально-приёмочного тестирования (всё равно автоматическиого)
V>т.е. тут сплошь и рядом происходит путаница
V>юнит-тестирование V>функциональное-тестирование V>регрессионное-тестирование
Да, я заметил, что тут происходит путаница. Собственно ЮТ со статическими входными /выходными данными и есть, фактически, регрессионный тест для некоторого отдельного модуля.
V>при определённых условиях любая пара тестов из трёх могут совпадать.. V>т.е. разница довольно тонкая.. V>несмотря на это больше всего шума и PR а вокруг unit-тестов
Хотя от них меньше всего пользы
FDS>>2. ЮТ, как средство указанного вами контроля за изменениями может потребовать изменения, так как, скажем, вместо "hellow world" в нашей программе через некоторе время потребуется выводить "hello Petia". И этот ЮТ полетит на свалку.
V>мой — не полетит V>мой подход (со сваливанием результатов файл) позволяет быстро проконтроллировать что поменялось в эталонах V>и одним действием актуализировать все эталоны по новым результатам
При этом эта актуализация требует ручной проверки результата на эталонность — мы и сказали — недостаток.
FDS>>Следующий ЮТ, опят же, может быть написан только после того, как программист проверит вручную правильность выдачи hello Petia и исправит или напишет новый ЮТ.
V>зачем новый ЮТ то ?
На новый модуль новый ЮТ. Или вы одним ЮТ собираетесь все модули тестировать?
FDS>>3. Это уже не ЮТ. ЮТ тестируют конкретный программный модуль, класс. FDS>>Всё остальное — это просто автоматизированный тест.
V>в общем да, хотя V>они могут и совпадать
Тут сошлись.
FDS>>Я то же иногда делаю полуавтоматические тесты, которые проверяют программный вывод, но они проверяют сразу всю программу, от начала до конца: загружают исходные данные, как это делает в начале работы пользователь, запускают некоторый цикл расчёта, сверяют результат с эталоном, который был получен и проверен программистом. Я бы это назвал Комплесным Тестом, так как 1. он не тестирует отдельный модуль, а тестирует всё программу, 2. в отличие от ЮТ он принципиально не может указать место ошибки — конкретный модуль, он может указать только наличие ошибки.
V>всё так, кроме того что: V>1. можно подбирать тестовые данные таким образом чтобы тестировать именно конкретный модуль
В моей практике подобрать так тестовые данные если и возможно, то слишком сложно с практической точки зрения.
V>2. можно на каждый модуль писать отдельный запускаемый файл с консольно-текстовым интерфейсом для его тестирования
Что, как я уже говорил не нужно при определённых условиях.
V>3. можно сами юнит-тесты реализовать так, чтобы вместо ассертов был вывод в файл
У меня когда-то был целый модуль, который создавал файловый лог ошибок с дополнительной информацией об ошибке. Что касается ассертов, я ими никогда не пользуюсь — все мои проверки одинаковы в релизных и отладочных версиях и основаны на исключениях. Если эти проверки не временные, конечно
V>в общем именно такой подход я и пытаюсь продвинуть своей тулзой
V>>>например пишет человек что то в program argument сразу в отладчике.. V>>>а почему там только одна строка? V>>>а почему не несколько чтобы можно было выбирать, или сразу даже подрят в разных вариантах запускать? V>>>и т.п.
FDS>>Это уже не к ЮТ относится.
V>ну относится/не относится уже дело десятое V>главное чтобы работать было удобно V>а как это называется, и насколько увязано пофиг
Но спорим мы сейчас именно о ЮТ и к спору это не относится.
Здравствуйте, FDSC, Вы писали:
FDS>Вы противоречите сами себе: раньше вы говорили, что результат будет получен после правильной отработки, теперь вы говорите, что тест может работать без этого результата (т.к. написали что "просто результат теста всё время разный"). Естественно, если тест проверяет результат по косвенным критериям, а не сравнением, то это возможно. Но тогда у него есть другой минус: его очень тяжело писать, иногда невозможно.
Тут vvaizh просто плохо выразился. Код теста всегда один и тотже (если интерфейс модуля не меняли), а вывод после изменения модуля может измениться.
Те нам не нужно менять код теста. Нам нужно только проверить очередной вывод теста на правильность.
Если использовать специализированные инструменты для нахождения различий в группе файлов и между двумя файлами то все делается очень просто и быстро.
Например с этой задачей очень хорошо справляется SVN. Прочто кладешь то что печатают тесты в репозиторий и все.
FDS>Если вы согласны с тем, что это нужно сделать целый один раз, т.е. получить правильную часть программы сначала без ЮТ или вручную получить правильный результат, то да. Мы и говорим, что сначала нам нужно тестировать всё в ручную, а потом использовать ЮТ, ПОСЛЕ ручного тестирования, фактически, как регрессионный тест. Данный пункт и призван вам показать этот недостаток вами же предложенного варианта со статическими входными данными: программа должна быть написана сначала без ЮТ, с помощью ручного тестирования.
Для того чтобы протестировать в ручную нужны какието тестовые данные. Какойто код. Их всеравно придется создавать чтобы на этом деле погонять код. Как отладить иначе я не знаю.
А теперь ответь на вопрос: Что мешает это дело сразу оформить в виде теста?
Вот напрмер один из моих тестов. (описание ITest опущено ибо не существенно для нашего разговора)
class Program
{
static void Main(string[] args)
{
DomainTest test = new DomainTest();
test.Writer = Console.Out;
test.RunTest();
}
}
После того как я все отладил я запустил все тесты включая этот. Запускалка тестов во всех папках проекта включая вложенные ищет сборки в которых есть наследники класса Test далие в определенном каталоге создает файл с именем полным именем теста (включая пространство имен), направляет Writer в этот файл и через отражение запускает все методы помеченые атрибутом [Test].
При помощи SVN я посмотрел что изменилось. Добавился только файл с выводом этого теста.
После чего я все закомитил.
Все. Модуль и тест к нему готовы.
Тест получился как побочный продукт отладки кода. Оверхед по сравнению с простым консольным приложением практически равен нулю.
Пока я не дошол до такой методики меня самого ломало тесты писать. А таким образом почему бы и нет? Всеравно отладочный код писать то почему бы его не оформить в виде теста?
FDS>При этом эта актуализация требует ручной проверки результата на эталонность — мы и сказали — недостаток.
Не ручной. Этим версионник занимается.
При помощи TortoiseSVN смотрел изменения в исходниках? Вот тут делаешь точно также только смотришь не исходники, а то что печатают тесты.
FDS>На новый модуль новый ЮТ. Или вы одним ЮТ собираетесь все модули тестировать?
На один и тотже модуль один и тотже ЮТ. Просто смотришь что в выоде и все. Если так и задумано то просто комитишь этот вывод. Если нет то исправляешь.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Cyberax, Вы писали:
C>minorlogic wrote: >> Вот на эту мысль я и пытался навести , что тестировать наиболее удобно >> маленькие отдельные модуле , а если сам тест встроен еще и в исполняемый >> код , то это почти идеально. И разделять юнит тесты в некое отдельно >> приложение не всегда разумно. C>Ыыы... Ну вообще-то юнит-тесты — это как раз и есть наборы небольших C>тестов, часто встраиваемых в сам код модуля (в Питоне, например).
Здравствуйте, FDSC, Вы писали:
FDS>Вы можете так же посмотреть в этой теме топик "Что такое ЮТ" — там я привёл свойство, которым по моему мнению, обладают ЮТ:
да, действительно, собственно почитал целиком, действительно спорить нам с вами не о чем,
в основном мннения совпадающие
Давайте назовем неким красивым словом разумное использование ассертов , типа самотестирующийся код (СК).
Преимущества дере юнит тестами (ЮТ) и контрактами (К).
1.Локальность.
ЮТ только стремятся быть локальными и тестировать каждый модуль отдельно. Но это не всегда возможно и очень часто НЕУДОБНО. СК — локален абсолютно , для него открыты все внутренности классов и модулей в отличие от ЮТ. СК работают напрямую с имплементацией в отличие от ЮТ.
Преимуществ перед К , я тут не вижу.
2. Обработка ВСЕХ данных и ВСЕХ веток программного кода.
ЮТ стремится к покрытию всех данных и всех веток кода , но это СЛОЖНО. Намного проще вместо заумных хаков и зубобробительных тестов на ограниченном наборе входных данных , просто тестировать с помощью наборов неких сценариев использования , а валидация обработки осуществляется самими модулями. Собственно если применять СК по полой программе, то юнит тесту останется лишь максимально покрыть код сценариями использования. Плюс ЛЮБОЙ запуск программы теперь становится нашим тестом ! Представте насколько вырастает к-во оттестированных ситуаций. Любой пользователь вашего модуля становится вашим тестером (халява)!
Если К выполняются статическим анализом , то понятное дело это совершенно не идет в сравнение с димамическим.
Хотя и понятно , что стат анализ способен выявить , то что неспособен динамический и наоборот.
3. Встроенность в код.
Вероятно многие знают , насколько это геморойно , изменяя код ,переписывать и юнит тесты. Это может просто ЗЛИТЬ, чувство потерянного впустую времени. Опять же совершенно естественная ситуация когда юнит тесты устаревают и становятся непригодными.
В случае СК такого просто не происходит , мы ЛОКАЛЬНО поменяли логику и тутже на месте локально изменили проверки, это на порядок меньше грузит. То же можно сказать и о К.
4. Постепенный рефакторинг , вместо полного переписывания.
Часто встречал такую мысль: Этот код не был приспособлен к юнит тестам , и его легче полностью переписать заново , чем приспособить к юнит тестированию. при использовании СК , такой проблемы нет (следствие пункта 1).
Опять хочу отдельно отметить, что самым разумным считаю СОЧЕТАНИЕ всех методик. Но совершенно неразумно забывать какие грандиозные преимущества дает СК, ОСОБЕННО это касается разработки в экстремальных ситуациях , нехватка времени , и т.п.
ПРИМЕР 1:
1.
Обнаружено , что в программе функция размытия изображения является узким местом. Решено заменить некого гауса на быстрое размытие.
2.
Возникает необходимость написать функцию быстрого размытия. Это не так просто как может показаться , надо учитывать прозрачность и работу к границами изображения.
3.
Реализуется в лоб самая ПРОСТАЯ функция размытия которая даже не пытается быть быстрой , а пытается быть только ПРАВИЛЬНОЙ. Это сделать достаточно легко (относительно , во всяком случае если известем алгоритм).
4.
Затем реализуется быстрая функция, использующая более сложный алгоритм, кучу адресной арифметики и т.п.
5.
Внедряется код который после работы быстрой функции запускает медленную и правильную , и сравнивает результирующее изображение попиксельно. Вот теперь каждый запуск нашей программы с использованием этой функции является и тестом. На этом этапе мы избавляемся от мелких багов кодирования как первой функции так и второй. Они работают по разным алгоритмам , поэтому нереально , чтобы опечатки в обоих версиях внесли одинаковую ошибку.
6. Прямо в коде пишется небольшой тест который проверяет граничные случае, размытие изображения 0x0 размытие изображения 1x1, 1x100, 100x1 и т.п. Этот замечательный тест запускается при первом обращении к функции размытия и выполняется только один раз на запуск (напрмиер контролируется статической переменной).
Это наш регрешен о котором даже не надо заботится, не надо запускать его каждый раз после внесения изменений и т.п.
7. Про головную боль с функцией размытия можно забыть на ДООЛГОЕ время, а ведь поверьте ошибки в таких функциях живут десятки лет в очень извесных библиотеках , хотя бы потому что определить правильно ли все выполняется не так просто , и на глаз не всегда видно. Иногда шаг 5 выключается одним движением руки , чтобы не сильно тормозить, но включается обратно , если падает подозрение на работу функции.
Здравствуйте, minorlogic, Вы писали:
M>6. Прямо в коде пишется небольшой тест который проверяет граничные случае, размытие изображения 0x0 размытие изображения 1x1, 1x100, 100x1 и т.п. Этот замечательный тест запускается при первом обращении к функции размытия и выполняется только один раз на запуск (напрмиер контролируется статической переменной). M>Это наш регрешен о котором даже не надо заботится, не надо запускать его каждый раз после внесения изменений и т.п.
Очень крутое решение для мультипоточности. И для длительно выполняющихся операций. И для операций, работающих с внешними ресурсами (файлами, сокетами, портами ввода-вывода, базами данных и пр.).
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, minorlogic, Вы писали:
M>>6. Прямо в коде пишется небольшой тест который проверяет граничные случае, размытие изображения 0x0 размытие изображения 1x1, 1x100, 100x1 и т.п. Этот замечательный тест запускается при первом обращении к функции размытия и выполняется только один раз на запуск (напрмиер контролируется статической переменной). M>>Это наш регрешен о котором даже не надо заботится, не надо запускать его каждый раз после внесения изменений и т.п.
E>Очень крутое решение для мультипоточности. И для длительно выполняющихся операций. И для операций, работающих с внешними ресурсами (файлами, сокетами, портами ввода-вывода, базами данных и пр.).
Здравствуйте, eao197, Вы писали:
E>Очень крутое решение для мультипоточности. И для длительно выполняющихся операций. И для операций, работающих с внешними ресурсами (файлами, сокетами, портами ввода-вывода, базами данных и пр.).
Объясните плз о чем вы ?
Если о том что предложенный пример и подход не покрывает все случаи жизни , и не является серебряной пулей ?
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, FDSC, Вы писали:
FDS>>Вы противоречите сами себе: раньше вы говорили, что результат будет получен после правильной отработки, теперь вы говорите, что тест может работать без этого результата (т.к. написали что "просто результат теста всё время разный"). Естественно, если тест проверяет результат по косвенным критериям, а не сравнением, то это возможно. Но тогда у него есть другой минус: его очень тяжело писать, иногда невозможно. WH>Тут vvaizh просто плохо выразился. Код теста всегда один и тотже (если интерфейс модуля не меняли), а вывод после изменения модуля может измениться. WH>Те нам не нужно менять код теста. Нам нужно только проверить очередной вывод теста на правильность. WH>Если использовать специализированные инструменты для нахождения различий в группе файлов и между двумя файлами то все делается очень просто и быстро. WH>Например с этой задачей очень хорошо справляется SVN. Прочто кладешь то что печатают тесты в репозиторий и все.
Он, собственно, ни плохо выразился, а перескочил с одого вида тестов на другие (см. ниже напишу)
FDS>>Если вы согласны с тем, что это нужно сделать целый один раз, т.е. получить правильную часть программы сначала без ЮТ или вручную получить правильный результат, то да. Мы и говорим, что сначала нам нужно тестировать всё в ручную, а потом использовать ЮТ, ПОСЛЕ ручного тестирования, фактически, как регрессионный тест. Данный пункт и призван вам показать этот недостаток вами же предложенного варианта со статическими входными данными: программа должна быть написана сначала без ЮТ, с помощью ручного тестирования. WH>Для того чтобы протестировать в ручную нужны какието тестовые данные. Какойто код. Их всеравно придется создавать чтобы на этом деле погонять код. Как отладить иначе я не знаю. WH>А теперь ответь на вопрос: Что мешает это дело сразу оформить в виде теста?
Я и не спорю. Просто мы разговаривали про другой тип тестов. Ваш тип теста даёт входные параметры и по косвенным признакам (насколько я понял) даёт ответ: правильное исполнение или нет. Мы разговаривали (по крайней мере сачала) про тесты, которым дают входные и выходные данные, уже полученные и проверенные.
1. У тестов, которые выполняют проверку по косвенным признакам есть недостаток: из очень сложно писать (по крайней мере в тех программах, которые я пишу), но с помощью них можно проверить программу, которую ещё никто не проверял. Кстати, эти тесты ещё и могу дать ложные срабатывания.
2. У тестов со статическими данными есть другой недостаток, о котором я и говорил: требуется ручная проверка.
Если вы говорите про что-то другое, то я вас не понял.
WH>После того как я все отладил я запустил все тесты включая этот. Запускалка тестов во всех папках проекта включая вложенные ищет сборки в которых есть наследники класса Test далие в определенном каталоге создает файл с именем полным именем теста (включая пространство имен), направляет Writer в этот файл и через отражение запускает все методы помеченые атрибутом [Test]. WH>При помощи SVN я посмотрел что изменилось. Добавился только файл с выводом этого теста. WH>После чего я все закомитил. WH>Все. Модуль и тест к нему готовы. WH>Тест получился как побочный продукт отладки кода. Оверхед по сравнению с простым консольным приложением практически равен нулю. WH>Пока я не дошёл до такой методики меня самого ломало тесты писать. А таким образом почему бы и нет? Всеравно отладочный код писать то почему бы его не оформить в виде теста?
Насколько я понял, вы вообще пишете только дамп решения. Я это то же делаю, только это делается уже для окончательного решения (для всей программы) и такой тест у меня уже не является ЮТ, так как он тестирует всю программу, а не отдельные модули, но это не так важно.
Насколько я понял, ваш тест является в общем-то регрессионным ЮТ.
Опять же, судя по вашим исходникам (поторопился удалить), первый результат вы не проверяете автоматически (если я правильно понял). Вы его только дампите. Значит результат должен быть правилен и вы это можете проверить только вручную или написав другой тест. Написание этого другого теста для меня в большинстве случаев совершенно неприемлимо, так как на это уходит времени больше (иногда гораздо больше), чем на первичное кодирование самого модуля (я замерял). А если проверять первичные результаты в ручную и получается недостаток, о котором мы говорили: необходима первичная ручная отладка для получения правильного эталона. И при каждом изменении эталона отладка должна повторяться. Другое дело, эталон изменяется не так часто, как сам модуль.
FDS>>При этом эта актуализация требует ручной проверки результата на эталонность — мы и сказали — недостаток. WH>Не ручной. Этим версионник занимается. WH>При помощи TortoiseSVN смотрел изменения в исходниках? Вот тут делаешь точно также только смотришь не исходники, а то что печатают тесты.
Опять же не совсем про то. Там где сравниваются два файла — эталонный и тестировочный — это делается автоматически. Но как только мы изменили модуль так, что эталон уже неправилен, требуется его коррекция. Так или иначе, для этого нужен специальный тест + обязательно ручная проверка, так как тест может и не сработать. SVN сдесь уже не поможет , а жаль
FDS>>На новый модуль новый ЮТ. Или вы одним ЮТ собираетесь все модули тестировать? WH>На один и тотже модуль один и тотже ЮТ. Просто смотришь что в выоде и все. Если так и задумано то просто комитишь этот вывод. Если нет то исправляешь.
Ну да, а на новый модуль — новый ЮТ (имеется ввиду совсем другой модуль). Тут я так понимаю, полное согласие.
Я вобще не адепт TDD и мне нужны тесты не для того чтобы проверить корректность программы, а для того чтобы они показали что что-то изменилось.
FDS>Опять же, судя по вашим исходникам (поторопился удалить), первый результат вы не проверяете автоматически (если я правильно понял). Вы его только дампите. Значит результат должен быть правилен и вы это можете проверить только вручную или написав другой тест.
Я в ручную отлаживаю систему и паралельно делаю дамп решения.
Далие этот дамп будет сравниваться с дампами после изменения системы.
Если дампы не совпали то начинаем разбиратся что произошло.
FDS>А если проверять первичные результаты в ручную и получается недостаток, о котором мы говорили: необходима первичная ручная отладка для получения правильного эталона.
Почему недостаток? Я отлаживаю систему до того состояния чтобы дамп был правильный.
Далие этот дамп служит эталоном.
Иногда делаю несколько дампов с разными входными данными.
FDS>И при каждом изменении эталона отладка должна повторяться.
А как иначе?
FDS>Другое дело, эталон изменяется не так часто, как сам модуль.
Вот именно. Если ничего не сломалось то дамп изменятся не будет.
А если сломалось то тут хочешь не хочешь, а проверить систему придется. К счастью дамп довольно хорошо локализует проблему.
FDS>Ну да, а на новый модуль — новый ЮТ (имеется ввиду совсем другой модуль). Тут я так понимаю, полное согласие.
Ну да новый модуль — новая дампилка.
Дампилка пишется в фоновом режиме во время отладки.
Тем болие что имея правильные инструменты написание дампилки превращается в очень простое занятие.
Например эти две строки:
foreach (IElementBase el in type.FilteredElements<IElementBase>())
DumpObject(el, 10);
генерируют 296 строк весьма читабельного дампа.
На таких объемах если что-то сбойнет то мы тутже получим фейерверк в версионнике.
Чего собственно и добивались.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Итак.
В принципе, всё правильно. Но должен заметить, что есть одна категория задач, где юнит тесты рулят не подецки, т.к. хорошо вписываются в процесс и являются очень логичным и мощным дополнением как при разработке, так и при сопровождении.
Этот класс задач — всевозможные фреймворки, библиотеки, компиляторы и прочая хрень для которой, чтобы её протестировать нужно по любому написать код. Вот таким кодом и могут являться ЮТ. Ведь трудно представить, что разработчик функции strlen написал её с чистого листа и ни разу не запустил её из какой-нибудь тестовой програмки, протестировав при этом возможные сценарии использования. Так почему это не делать сразу в виде ЮТ? В качестве побочного эффекта получаем возможность проверки планируемой работоспособности системы при внесении изменений.
Что же касается "Biznizz Lojig", то в большинстве случаев дело обстоит именно так, как ты говоришь. Это дорого, это тормозит девелопмент, это тебует дисциплины, это не работает в условиях сокращения сроков и пресняка. Этот стройный дворец из песка моментально рушится и теряет всякий смысл, как только в списке тестов появляется хотя бы один красный кружочек, на который забивают. Тут так, либо всё зелёное, либо можно уже не париться. Добиться этого в условиях работы в среднестатистической команде крайне сложно.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
IT>Что же касается "Biznizz Lojig", то в большинстве случаев дело обстоит именно так, как ты говоришь. Это дорого, это тормозит девелопмент, это тебует дисциплины, это не работает в условиях сокращения сроков и пресняка. Этот стройный дворец из песка моментально рушится и теряет всякий смысл, как только в списке тестов появляется хотя бы один красный кружочек, на который забивают. Тут так, либо всё зелёное, либо можно уже не париться. Добиться этого в условиях работы в среднестатистической команде крайне сложно.
Здравствуйте, minorlogic, Вы писали:
E>>Очень крутое решение для мультипоточности. И для длительно выполняющихся операций. И для операций, работающих с внешними ресурсами (файлами, сокетами, портами ввода-вывода, базами данных и пр.).
M>Объясните плз о чем вы ?
О том, что выполнение каких-то действий "под ковром", на мой взгляд, является не самой хорошей идеей. Если я открываю файл, мне не хочется столкнуться с тем, что функция ifstream::open где-то там в нутрях проведет пару своих unit-тестов. Или если я один раз в программе шифрую блок данных алгоритмом RSA с длиной ключа 4K, то мне не хочется, чтобы реализация алгоритма еще и протестировала себя на каких-то других ключаях.
Кроме того, в многопоточных программах использование общего статического флага-признака самотестирования будет требовать средств синхронизации доступа к этому флагу. И вообще: представим, что на шести нитях я одновременно обратился к RSA-шифрованию. Должна ли самопроверка идти одновременно шесть раз? Или же пять нитей должны подождать, пока одна проведет проверку? Или одна будет проводить проверку, а пять остальных пойдут шифровать в надежде на то, что первая никаких проблем не обнаружит?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
M>>Объясните плз о чем вы ?
E>О том, что выполнение каких-то действий "под ковром", на мой взгляд, является не самой хорошей идеей. Если я открываю файл, мне не хочется столкнуться с тем, что функция ifstream::open где-то там в нутрях проведет пару своих unit-тестов. Или если я один раз в программе шифрую блок данных алгоритмом RSA с длиной ключа 4K, то мне не хочется, чтобы реализация алгоритма еще и протестировала себя на каких-то других ключаях.
E>Кроме того, в многопоточных программах использование общего статического флага-признака самотестирования будет требовать средств синхронизации доступа к этому флагу. И вообще: представим, что на шести нитях я одновременно обратился к RSA-шифрованию. Должна ли самопроверка идти одновременно шесть раз? Или же пять нитей должны подождать, пока одна проведет проверку? Или одна будет проводить проверку, а пять остальных пойдут шифровать в надежде на то, что первая никаких проблем не обнаружит?
Ну можно и не такие сложности себе создать , но зачем ? Или вы не можете думать сами и необходим сборник зазубреных правил , каждое из которых можно довести до абсурда ?
Здравствуйте, minorlogic, Вы писали:
M>Ну можно и не такие сложности себе создать , но зачем ? Или вы не можете думать сами и необходим сборник зазубреных правил , каждое из которых можно довести до абсурда ?
Перечислите, пожалуйста критерии, основываясь на которых можно принять решение о встраивании в какую-то функцию/библиотеку неявного (для пользователя) запуска внутренних проверочных тестов при первом обращении к функции/библиотеки?
Ну или хотя бы пять-десять примеров функций, в которых подобные тесты по вашему мнению были бы оправданными.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
E>Перечислите, пожалуйста критерии, основываясь на которых можно принять решение о встраивании в какую-то функцию/библиотеку неявного (для пользователя) запуска внутренних проверочных тестов при первом обращении к функции/библиотеки?
E>Ну или хотя бы пять-десять примеров функций, в которых подобные тесты по вашему мнению были бы оправданными.
В библиотеку,как в набор функций, наверное, действительно ничего встраивать не нужно.
В библиотеку, как в модуль — уже встраивать можно.
Возьмем ранее упоминавшийся графический движок — если он будет для каждого 100-го кадра в background-е проверять правильность вывода, через тот же более простой, но более медленный алгоритм, то ничего страшного не случится.
при этом мы будем иметь постоянную обратную связь с реального применения граф. движка.
Здравствуйте, DarkGray, Вы писали:
DG>В библиотеку, как в модуль — уже встраивать можно.
Если только эти методы должны будут вызываться явно. Например, наличие метода self_test вполне может оказаться востребованным.
DG>Возьмем ранее упоминавшийся графический движок — если он будет для каждого 100-го кадра в background-е проверять правильность вывода, через тот же более простой, но более медленный алгоритм, то ничего страшного не случится.
Кто об этом будет судить -- разработчик или пользователь библиотеки?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
E>>Кто об этом будет судить -- разработчик или пользователь библиотеки?
DG>сильно зависит от такого насколько важно качество против скорости, или наоборот.
Вы не ответили. У разработчика может быть своя оценка этого соотношения, а у пользователя своя. Какую нужно предпочесть априори?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, minorlogic, Вы писали:
M>ЮТ только стремятся быть локальными и тестировать каждый модуль отдельно. Но это не всегда возможно и очень часто НЕУДОБНО.
Есть Юнит тесты, есть интеграционные тесты. Провести между ними грань практически невозможно, потому как непонятно, то ли мы тестируем один модуль на основе данных второго модуля в предположении что второй точно работает, то ли мы тестируем оба модуля и как они работают вместе. Тут все скользко, и я особо их не разделяю между собой(кроме случая когда делаются модули различными группами). M>СК — локален абсолютно , для него открыты все внутренности классов и модулей в отличие от ЮТ.
И это недостаток. У нас тесты будут зависимы именно от реализации, а не от результата. Как результат, любая адаптация реализации понесет за адаптацию тестов в лучшем случае. В худшем, поскольку они могут находится в любой части кода — непонятному появляению assert когда все хорошо работает.
M>Плюс ЛЮБОЙ запуск программы теперь становится нашим тестом ! Представте насколько вырастает к-во оттестированных ситуаций. Любой пользователь вашего модуля становится вашим тестером (халява)!
А нужно ли это пользователю? Для того чтобы обеспечивать корректную информацию об ошибках в процессе работы пользователя — нужно строить совершенно другие механизмы. В котором есть информация предназначенная пользователю, а есть информация предназначенная службе сопровождения/разработки.
M>3. Встроенность в код. M>Вероятно многие знают , насколько это геморойно , изменяя код ,переписывать и юнит тесты. Это может просто ЗЛИТЬ, чувство потерянного впустую времени.
Не изменяя код. А изменяя интерфейс или функциональность. Это очень разные вещи. К тому же, обычно кто реализует, тот и пишет тест.
M>4. Постепенный рефакторинг , вместо полного переписывания. M>Часто встречал такую мысль: Этот код не был приспособлен к юнит тестам , и его легче полностью переписать заново , чем приспособить к юнит тестированию. при использовании СК , такой проблемы нет (следствие пункта 1).
Есть два подхода. 1. Писать сразу начиная с unit-тестов тестируемый код. 2. После того как написал думать о том, как бы присобачить unit-тесты ко всей этой шараге функций. В данном случае ты говоришь именно о нетестиремом коде, и в этом случае уже нужно считать сколько-что будет стоить, и на фиг это нужно.
M>Опять хочу отдельно отметить, что самым разумным считаю СОЧЕТАНИЕ всех методик. Но совершенно неразумно забывать какие грандиозные преимущества дает СК, ОСОБЕННО это касается разработки в экстремальных ситуациях , нехватка времени , и т.п.
Например, когда отдают клиентам дебугнутые версии. Потому как релиз проверить решили в последний момент, за что и поплатились.
M>ПРИМЕР 1:
Ничего не понял. У тебя задача построить корректный алгоритм размытия. У тебя есть условия — границы, прозрачность. У тебя есть алгоритм который ты считаешь корректным. Так что тебе мешает проверить новый алгоритм на условия с помощью unit-тестов на этапе реализации?
DG>>сильно зависит от такого насколько важно качество против скорости, или наоборот.
E>Вы не ответили. У разработчика может быть своя оценка этого соотношения, а у пользователя своя. Какую нужно предпочесть априори?
я ответил.
могу ответить более определенно — не знаю.
Здравствуйте, DarkGray, Вы писали:
DG>я ответил. DG>могу ответить более определенно — не знаю.
Так по моему мнению получается, что вы навязываете пользователю выбор разработчика.
Давайте доведем ситуацию до маразма: пусть библиотека каждый сотый кадр обсчитывает дважды и проверяет результаты. Пусть на это уходит минута (вот такие у меня кадры большие и сложные ). Если я обсчитываю 10000 кадров, то получится, что я буду тратить 100 лишних минут (больше полутора часов). А если я это делаю на арендованом SGI или Sun кластере, каждый лишний час мне обходится в $100? И обсчет я делаю не один раз. Получится, что купленная у вас библиотека будет обходиться мне не только в однажды уплаченную сумму, но еще и в дополнительные накладные расходы при ее использовании. Вот и спрашивается, нафига мне такая библиотека?
Другое дело, если бы я мог скомпилировать ее с неким флагом DEBUG_EVERY_100 и только тогда эта проверка бы осуществлялась. Тогда бы я знал, за что плачу.
В противном же случае получается анекдот:
Билл Гейтс в Мак Дональдсе.
Билл: — Мне, пожалуйста, один Биг Мак
Продавец: — Один Биг Мак, одна Кола, вместе 6.99
Б: — Но я просил только Биг Мак!
П: — Кола идет вместе с Маком как часть единого пакета.
Б: — Что? За Колу я платить не буду!
П: — И не надо! Кола предоставляется абсолютно бесплатно!
Б: — Но ведь один Биг Мак стоил до сих пор 3.99!
П: — Теперь Биг Мак имеет новые возможности! Он поставляется вместе с Колой!
Б: — Я только что выпил Колу! Мне не нужна еще одна!
П: — Тогда вам придется отказаться и от Биг Мака.
Б: — Ладно, я плачу 3.99 и отказываюсь от Колы.
П: — Вы не можете разделять части пакета! Биг Мак и Кола тесно интегрированы!
Б: — Чушь! Мак и Кола — два различных продукта!
П: — Тогда посмотрите (Топит Биг Мак в Коле)
Б: — Что вы делаете?!
П: — Это в интересах покупателей! Только так мы можем гарантиповать целостность вкуса всех компонентов пакета.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Я пытался всего лишь показать, что не всё так лекго, как было сказано:
нам не нужно его "формировать"
нам нужно :
1. запустить один раз тест,
2. проконтроллировать глазками что тест на выход выдал правильный результат
3. банально объявить этот результат эталонным
всё это выполняется буквально несколькими нажатиями клавиши/мышки
Вот это "2. проконтроллировать глазками что тест на выход выдал правильный результат" не выполняется несколькими нажатиями и из-за этого весь спор и возник.
Я уж не говорю про то, что просто не представляю как найти с пом. ЮТ такие ошибки, частично их может найти только человек (GUI), частично, статический верификатор:
1. 20.07.06
В файле VinUnicode найден код, не приводящий к закрытию открытого файла
if NOT _CreateFile(FileName, hFile) then exit;
FileSize := length(Content);
if FileSize = 0 then exit;
Найдено после замены части кода на вызов функции
Решение:
переупорядочивание вызовов
FileSize := length(Content);
if FileSize = 0 then exit;
if NOT _CreateFile(FileName, hFile) then exit;
ВНИМАНИЕ:
В GetPosElementByIndex нумерация Index изменена и начинается с 1!
2. 20.07.06 Там же
Неправильный возвращаемый код при возврате в начале функции.
Решение: строка result := 1 в начале функций заменена на result := 0
В конце функций добавлена строка result := 0
---------------------
29.07.2006
1. Вызов функции GetModuleFileNameExW с параметром hinstance.
Функция вызывалась в секции инициализации модуля, тогда как hIsntance
инициализировалась только в начале выполнения программы.
Решение: замена hIstance на вызов GetModuleHandle(nil)
2. При перезапуске explorer иконка на панели задач не выводилась заново
Решение: обработка сообщения RegisterWindowMessage('TaskbarCreated');
3. При запуске программы из реестра (вместе с процедурой входа пользователя)
программа не могла найти файл strings.ini
Источник проблемы: при запуске командной строкой из реестра была
установлена неправильная текущая директория
(видимо, K:\Documents and Settings\Vinuser)
Решение: смена текущей директории на нужную. См. функцию _SetCurrentDirectory;
в модуле InternalStrings
4. При смене текущей директории происходил вызов функции, выдающей полный путь
к файлу программы. Далее от конца строки вёлся поиск символа '\'.
Результат был неправильный, так как строка была unicode, а поиск вёлся
как будто строка ANSI
Решение: получение полного пути к файлу как ANSI-строки
5. Коммандная строка для запуска из реестра усекалась.
Причина проблемы: функция GetModuleFileNameExW возвращала количество
символов unicode, в то время как RegSetValueExW принимает длину
строки в байтах
30.07.2006
1. При перезапуске explorer и отсутствии связи с сервером появлялась зелёная
иконка (вместо красной — связь отсутствует).
Причина проблемы: иконка выводилась без учёта текущего статуса, с другой
стороны сама иконка меняет цвет только при смене статуса
Решение: при обработке соотв. сообщения вывод иконки производится с учётом
статуса связи с сервером
2. При записи командной строки в реестр длина строки, передаваемая в функцию
RegSetValueExW некорректна
Причина ошибки: функция RegSetValueExW принимает длину строки в байтах
с учётом терминального символа. Функция GetModuleFileNameExW выдаёт
длину строки (в символах) без учёта терминального символа.
Решение: добавление к размеру строки размера терминального символа
Последствия ошибки: никаких последствий не вызвала. Строка в реестре
одинакова как при учёте длины терминального символа, так и без него.
Строка в реестре не содержит последний символ строки и
терминального символа, если от длины строки без учёта
терминального символа отнять 2 (т.е. sizeof(WideChar))
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, DarkGray, Вы писали:
DG>>я ответил. DG>>могу ответить более определенно — не знаю.
E>Так по моему мнению получается, что вы навязываете пользователю выбор разработчика.
E>Давайте доведем ситуацию до маразма: пусть библиотека каждый сотый кадр обсчитывает дважды и проверяет результаты. Пусть на это уходит минута (вот такие у меня кадры большие и сложные ). Если я обсчитываю 10000 кадров, то получится, что я буду тратить 100 лишних минут (больше полутора часов). А если я это делаю на арендованом SGI или Sun кластере, каждый лишний час мне обходится в $100? И обсчет я делаю не один раз. Получится, что купленная у вас библиотека будет обходиться мне не только в однажды уплаченную сумму, но еще и в дополнительные накладные расходы при ее использовании. Вот и спрашивается, нафига мне такая библиотека?
1. Такую длительную проверку вряд ли кто-то будет вставлять
2. Проводить проверку или нет решает пользователь, если она занимает длительное время
3. Если результат значимый (я, например, занимаюсь расчётами на прочность), то некоторые проверки просто ОБЯЗАТЕЛЬНЫ и сколько они времени занимают уже не так важно. Разработчик всегда вставляет довольно быстрые проверки, а пользователь всегда хочет быть уверенным, что программа сделала всё возможное, для того, что бы недопустить выдачу некорректного результата там, где это недопустимо.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>>Итак.
IT>В принципе, всё правильно. Но должен заметить, что есть одна категория задач, где юнит тесты рулят не подецки, т.к. хорошо вписываются в процесс и являются очень логичным и мощным дополнением как при разработке, так и при сопровождении.
IT>Этот класс задач — всевозможные фреймворки, библиотеки, компиляторы и прочая хрень для которой, чтобы её протестировать нужно по любому написать код. Вот таким кодом и могут являться ЮТ. Ведь трудно представить, что разработчик функции strlen написал её с чистого листа и ни разу не запустил её из какой-нибудь тестовой програмки, протестировав при этом возможные сценарии использования. Так почему это не делать сразу в виде ЮТ? В качестве побочного эффекта получаем возможность проверки планируемой работоспособности системы при внесении изменений.
Ну дак, опят же, может разработчик не strlen проверяет, а сразу целый набор функций. Тогда это уже не ЮТ, это уже просто тестирование. Вот и вопрос: нужны они: ЮТ для каждой функции, или только для некоторых, которые сразу дают работу всем остальным.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, mbergal, Вы писали:
M>>А как насчет желтого?
IT>Я вообще не понимаю, какой смысл в жёлтом.
[Test, Ignore( "Misha> didn't have time to look at why it is failing after upgrading to new version of BLToolkit, SPb - please fix when done with ....." ) ]
public void test()
{
}
Индикатор статуса проекта у меня зеленый, т.е. инвариант (проект должен быть зеленым — сохраняется), с другой стороны мне ясно видно какие из тестов не up-to-date, и должны быть подняты.
Не буду рассуждать о безусловных преимуществах и фатальных недостатках TDD. Расскажу всего лишь один пример из жизни.
Начнем с того, что я очень люблю рефакторинг. Мне вобще кажется, что сложный код (а мы ведь здесь все специалисты именно по сложному коду, не так ли?), который не отрефакторили раза три, скорее всего будет не очень качественным. Поэтому на начальных этапах своей жизни мой код выполняет значительные пертурбации, прежде чем придет в сравнительно устойчивое состояние.
А в рефакторинге главное что? В рефакторинге главное простота его производства. Чем проще и дешевле рефакторинг, тем более глубоким он будет при тех же затраченных усилиях.
Теперь вернемся к тестам. По идее, согласно заветам классиков TDD, юнит тесты самое оно для рефакторинга. Но вот ведь незадача — любой мало мальски сложный рефакторинг гарантированно ломает тесты. Не потому, что в результате рефакторинга появились ошибки, но потому что тесты перестали отвечать реалиям жизни.
Смотрите что получается. Я, как и указано мудрыми мужами, пишу вначале тесты. Потом пишу реализацию. Потом начинаю ее интенсивно рефакторить и на каждом шаге натыкаюсь на сломанные тесты и необходимость эти тесты рефакторить. Причем, что забавно, рефакторить тесты автоматом одновременно с рефакторингом рабочего кода нельзя, ибо это нарушает главное правило юнит-тестов — проверочный код должен быть как можно более независим от кода тестируемого.
Итого, что я получаю. А получаю я немалое время, затраченное на написание тестов в самом начале, усложненный рефакторинг на каждом этапе, тысячи ложных срабатываний и одну-две реально отловленных тестами ошибок.
Вот такие вот пирожки.
P.S. По свидетельству знакомых, занимающихся тестированием профессионально, долго и успешно, стоимость хорошего покрытия тестами проекта составляет от 25 до 40 процентов от стоимости разработки того, что тестируют, в случае, если проект неплохо подходит для модульного тестирования. Если подходит плохо, то цифра может быть и 100%. Циферки заставляют задуматься, не правда ли?
... << RSDN@Home 1.2.0 alpha rev. 646 on Windows XP 5.1.2600.131072>>
Здравствуйте, FDSC, Вы писали:
FDS>1. Такую длительную проверку вряд ли кто-то будет вставлять
Разработчик может даже не предполагать условий, в которые поставит пользователь библиотеку.
FDS>2. Проводить проверку или нет решает пользователь, если она занимает длительное время
Вот именно. А если от пользователя это скрыто и никак на это повлиять нельзя, то...
FDS>3. Если результат значимый (я, например, занимаюсь расчётами на прочность), то некоторые проверки просто ОБЯЗАТЕЛЬНЫ и сколько они времени занимают уже не так важно. Разработчик всегда вставляет довольно быстрые проверки, а пользователь всегда хочет быть уверенным, что программа сделала всё возможное, для того, что бы недопустить выдачу некорректного результата там, где это недопустимо.
Мне кажется, что обязательные проверки результатов расчета, которые предусмотрены самой задачей и методом ее решения являются совершенно отличным от того, что предлагалось:
6. Прямо в коде пишется небольшой тест который проверяет граничные случае, размытие изображения 0x0 размытие изображения 1x1, 1x100, 100x1 и т.п. Этот замечательный тест запускается при первом обращении к функции размытия и выполняется только один раз на запуск (напрмиер контролируется статической переменной).
Это наш регрешен о котором даже не надо заботится, не надо запускать его каждый раз после внесения изменений и т.п.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, mbergal, Вы писали:
M>Индикатор статуса проекта у меня зеленый, т.е. инвариант (проект должен быть зеленым — сохраняется), с другой стороны мне ясно видно какие из тестов не up-to-date, и должны быть подняты.
В таком случае, это намного лучше чем красный. Но зелёный все равно лучше
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, minorlogic, Вы писали:
M>>ЮТ только стремятся быть локальными и тестировать каждый модуль отдельно. Но это не всегда возможно и очень часто НЕУДОБНО. GZ>Есть Юнит тесты, есть интеграционные тесты. Провести между ними грань практически невозможно, потому как непонятно, то ли мы тестируем один модуль на основе данных второго модуля в предположении что второй точно работает, то ли мы тестируем оба модуля и как они работают вместе. Тут все скользко, и я особо их не разделяю между собой(кроме случая когда делаются модули различными группами). M>>СК — локален абсолютно , для него открыты все внутренности классов и модулей в отличие от ЮТ. GZ>И это недостаток. У нас тесты будут зависимы именно от реализации, а не от результата. Как результат, любая адаптация реализации понесет за адаптацию тестов в лучшем случае. В худшем, поскольку они могут находится в любой части кода — непонятному появляению assert когда все хорошо работает.
Категорически не согласен.
Представим модуль ThreadPool у которого есть только функция add_task(). Как посредством только этого интерфейса можно оттестировать логику работы с потоками , как менеджер потоков реагирует на различные события , как увеличивает — уменьшает кво работающих потоков и т.п ?
Расскажите плиз , как бы вы тестировали такой модуль. ?
M>>Плюс ЛЮБОЙ запуск программы теперь становится нашим тестом ! Представте насколько вырастает к-во оттестированных ситуаций. Любой пользователь вашего модуля становится вашим тестером (халява)! GZ>А нужно ли это пользователю? Для того чтобы обеспечивать корректную информацию об ошибках в процессе работы пользователя — нужно строить совершенно другие механизмы. В котором есть информация предназначенная пользователю, а есть информация предназначенная службе сопровождения/разработки.
Ок. Мне и в голову не могло прити что ктонибудь может допустить мысль отдать конечному пользователю отладочный код , который используется в процессе разработке. Такую ситуацию я допускаю , но такой отладочный код является частью системы (напрмиер логирование неожиданных ситуаций) и к нему предъявляются такие же критерии качества как и к системе.
Под "пользователями" я подразумевал , ваших колег которые будут работать в процессе интеграции с вашим модулем , тестеры , и бета тестеры.
Мне кажется очевидным что тот регрессион из моего примера , необходимо запустить только один раз после внесения изменений , и выполняться каждый раз у конечного пользователя — бессмысленно.
Из этих соображений существуют понятия релизной и дебаговой сборки , макросы компиляции и т.д.
Все о чем я говорил — это только для разработчика в процессе разработки.
M>>3. Встроенность в код. M>>Вероятно многие знают , насколько это геморойно , изменяя код ,переписывать и юнит тесты. Это может просто ЗЛИТЬ, чувство потерянного впустую времени. GZ>Не изменяя код. А изменяя интерфейс или функциональность. Это очень разные вещи. К тому же, обычно кто реализует, тот и пишет тест.
Я уже говорил , и повторю что оттестировать изнутри можно намного эфективнее. Считаю что в этом вопросе вы не правы.
M>>4. Постепенный рефакторинг , вместо полного переписывания. M>>Часто встречал такую мысль: Этот код не был приспособлен к юнит тестам , и его легче полностью переписать заново , чем приспособить к юнит тестированию. при использовании СК , такой проблемы нет (следствие пункта 1). GZ>Есть два подхода. 1. Писать сразу начиная с unit-тестов тестируемый код. 2. После того как написал думать о том, как бы присобачить unit-тесты ко всей этой шараге функций. В данном случае ты говоришь именно о нетестиремом коде, и в этом случае уже нужно считать сколько-что будет стоить, и на фиг это нужно.
А подхол с СК , вы не включили в этот перечень ? Мне кажется существует намного больше подходов чем два, и не вижу причин почему СК может не применяться везде где это можно (но не более того).
M>>Опять хочу отдельно отметить, что самым разумным считаю СОЧЕТАНИЕ всех методик. Но совершенно неразумно забывать какие грандиозные преимущества дает СК, ОСОБЕННО это касается разработки в экстремальных ситуациях , нехватка времени , и т.п. GZ>Например, когда отдают клиентам дебугнутые версии. Потому как релиз проверить решили в последний момент, за что и поплатились.
Ну бывает и такое , а какое отношение это имеет к предыдущему разговору. Я кстати знаю массу проектов где релизная сборка просто не нужна , нет никаких тербований по производительности ... И даже слышал что некоторые проекты вообще релизной не пользуются.
M>>ПРИМЕР 1: GZ>Ничего не понял. У тебя задача построить корректный алгоритм размытия. У тебя есть условия — границы, прозрачность. У тебя есть алгоритм который ты считаешь корректным. Так что тебе мешает проверить новый алгоритм на условия с помощью unit-тестов на этапе реализации?
Да вообще ничиго! Я не считаю принципиальным создать отдельный проект с заумным названием юнит тест , если я могу все что мне надо оттестировать на месте.
Преимущества я писал , вы не согласны. Мне реально хочется узнать почему , и если можно с маааленьким примером. Я не уверен в своей правоте на 100% , и поэтому хочется послушать коментарии по делу. Ваш пост пока один по делу , спасибо.
P.S. не думаю что смогу сформулировать догматичные правила по СК. Вот например недавно я оставил в релизном варианте кода проверки такого плана.
Текстовая строка кодируется определенным образом , потом обратной функцией декодируется. Обе функции внутри себя проверяют коректность кодирования через декодирование и наоборот , и если произошла ошибка — функция возврашаерт ошибку.
Это пример когда производительность меня совершенно на порядки меньше интересовала чем коректность. И прежде чем этот код пойдет к клиенту , я знаю что он проработает сотни тысяч раз в процессе разработки, но и в релизном варианте , пускай лучше код вернет ошибку и я буду о ней знать (с описанием) чем код будет работать неправильно у клиента и я не смогу даже примено идентифицировать баг.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Lazy Cjow Rhrr, Вы писали:
AVK>Начнем с того, что я очень люблю рефакторинг. Мне вобще кажется, что сложный код (а мы ведь здесь все специалисты именно по сложному коду, не так ли?), который не отрефакторили раза три, скорее всего будет не очень качественным. Поэтому на начальных этапах своей жизни мой код выполняет значительные пертурбации, прежде чем придет в сравнительно устойчивое состояние. AVK>А в рефакторинге главное что? В рефакторинге главное простота его производства. Чем проще и дешевле рефакторинг, тем более глубоким он будет при тех же затраченных усилиях.
Refactoring is the process of rewriting a computer program or other material to improve its structure or readability, while explicitly preserving its meaning or behavior. Neil Roodyn recommends that "if you refactor, you should also have test fixtures in place: They can validate that your refactorings don't change the behavior of your software."
http://en.wikipedia.org/wiki/Refactoring
AVK>Теперь вернемся к тестам. По идее, согласно заветам классиков TDD, юнит тесты самое оно для рефакторинга. Но вот ведь незадача — любой мало мальски сложный рефакторинг гарантированно ломает тесты.
Значит плохо перерефакторили. Это они и ловят.
Вы наверное имели в виду не рафакторинг, а просто переписывание кода. Пока алгебра и простота не станут удовлетворять. Обычно такое переписывание это и редизайн — оно затрагивает не только один модуль а несколько и изменяет взаимодействие между ними.
AVK>Не потому, что в результате рефакторинга появились ошибки, но потому что тесты перестали отвечать реалиям жизни. Смотрите что получается. Я, как и указано мудрыми мужами, пишу вначале тесты. Потом пишу реализацию. Потом начинаю ее интенсивно рефакторить и на каждом шаге натыкаюсь на сломанные тесты и необходимость эти тесты рефакторить.
IMHO, UT и любые другие бесполезны когда происходит перепроектирование, и это OK. Единственные проблемы, которое это создает — это нарушание одного из инвариантов TDD, не пишем кода если не падает тест из-за чего и получаем битое test-coverage. Но это можно побороть другими методами если нужно.
AVK>Итого, что я получаю. А получаю я немалое время, затраченное на написание тестов в самом начале, усложненный рефакторинг на каждом этапе, тысячи ложных срабатываний и одну-две реально отловленных тестами ошибок. AVK>Вот такие вот пирожки.
Но без знания конкретного случая рецепты давать сложно: какова стоимость написания теста, почему она такая? Какая test strategy (что и как мы будем тестировать, как сделать так чтобы потратить мало но сделать (уменьшить риски) много, где ручками, functional or unit-test, где UI, где BLL а где libs/utilities.), как делается test coverage analysis и какая policy на изменение покрытия.
IMHO, возможно использовать тесты, так чтобы работа ускорилась.
AVK>P.S. По свидетельству знакомых, занимающихся тестированием профессионально, долго и успешно, стоимость хорошего покрытия тестами проекта составляет от 25 до 40 процентов от стоимости разработки того, что тестируют, в случае, если проект неплохо подходит для модульного тестирования. Если подходит плохо, то цифра может быть и 100%. Циферки заставляют задуматься, не правда ли?
Да нет, честно говоря не заставляет, потому что информации мало. Какого проекта? Какими тестами? К 100%? Да легко — я думаю что в MS (чтобы недалеко ходить) на некоторых проектах намного больще.
M>Refactoring is the process of rewriting a computer program or other material to improve its structure or readability, while explicitly preserving its meaning or behavior. Neil Roodyn recommends that "if you refactor, you should also have test fixtures in place: They can validate that your refactorings don't change the behavior of your software."
Думаешь, я этого не знал? Вопрос только в одном — на каком уровне мы фиксируем этот meaning or behavior. Далеко не факт, что на том же, на котором оперируют юнит-тесты.
Попробую объяснить более понятно. Пусть есть у нас некая система А, meaning&behavior которой определяются требованиями заказкика (замечу, тоже в довольно зыбких рамках, куда более зыбких, нежели формализм unit tests, ну да не суть). Система А состоит из компонентов В и С. На каждый из которых, разумеется, есть свои спецификации, проистекающие из требований заказчика, но уже в значительной степени определяемых и разработчиком. И на каждый компонент имеется достаточный набор тестов. Теперь, ввиду найденой ошибки, либо еще каких внутренних причин, но нам понадобилось существенно изменить код компонента В без сохранения M&B. При этом контракт В существенно меняется, однако набор требований к А не меняется. Является ли эта операция рефакторингом по отношению к В. Согласно приведенному тобой определению (хотя мне оно кажется неполным, но об этом чуть ниже) нет. А является ли это рефакторингом по отношению к А? Да, является, поскольку поведение системы в целом не изменилось, несмотря на изменение поведения одного из компонентов.
Теперь о том, почему это определение мне не нравится. Не нравится оно мне, потому что оно слишком узко. Мне так кажется, что балансировка в пределах нечетко очерченных рамок требований (а оно, как правило, так и есть) вполне отвечает духу понятия рефакторинга, а юнит-тесты в качестве способа, контроллирующего эти рамки, слишком формальны и прямолинейны. В конце концов, требования определяются человеком и утверждать, что их всегда заранее и на 100% выразить ввиде программного кода несколько самонадеянно, не находишь? А коль так, то юнит-тесты вполне имеют право эволюционировать в процессе разработки продукта.
AVK>>Теперь вернемся к тестам. По идее, согласно заветам классиков TDD, юнит тесты самое оно для рефакторинга. Но вот ведь незадача — любой мало мальски сложный рефакторинг гарантированно ломает тесты.
M>Значит плохо перерефакторили. Это они и ловят.
Да нет, не плохо. Прорефакторили хорошо. Но рефакторинг, который не затрагивает вобще ни одного публичного контракта, это слишком примитивный рефакторинг. Масса видов рефакторинга, наличествующего в распространенных средствах автоматизированного рефакторинга и описанных тем же Фаулером ломает контракт если не гарантированно, то очень часто. А коль так, то и юнит-тесты, завязанные на этот контракт, гарантированно будут сломаны. В лучшем случае тесты просто перестанут компилироваться. А в худшем нам придется тесты отлаживать.
M>Вы наверное имели в виду не рафакторинг, а просто переписывание кода.
Да назови как хочешь. Главное, что в этом случае тесты конкретно начинают мешать.
M>IMHO, UT и любые другие бесполезны когда происходит перепроектирование, и это OK.
Да, но как быть с TDD, предписывающим начинать проектирование с тестов? Что, писать по новой новый набор тестов при каждом редизайне? Это ж застрелиться просто! Писать тесты после того, как редизайн станет маловероятным в ближайшее время? Но это идет в разрез с принципами TDD.
M>Но это можно побороть другими методами если нужно.
Я всегда очень подозрительно отношусь к предложениям, когда в результате их использования начинаются проблемы, с которыми потом надо бороться. Есть хорошая русская пословица на эту тему про овечью шкуру и процесс ее химобработки, с целью придания означенной шкуре более приемлемых механических свойств.
M>Но без знания конкретного случая рецепты давать сложно: какова стоимость написания теста,
Тебе в чем, в шекелях?
M> почему она такая?
Интересный вопрос. Сродни — почему на небе звезды.
M> Какая test strategy (что и как мы будем тестировать,
Разрабатываемый продукт при помощи модульного тестирования.
M> как сделать так чтобы потратить мало но сделать (уменьшить риски) много,
То есть как побороться с граблями, которые только что самостоятельно заботливо прикопал. Может проще грабли не прикапывать?
M> где ручками, functional or unit-test,
Здесь о UT вобще то топик. С функциональным тестированием все просто — оно должно быть. От него не уйдешь никаким боком.
M>как делается test coverage analysis и какая policy на изменение покрытия.
Это все только увеличивает стоимость тестов. А она и так черезмерна.
M>IMHO, возможно использовать тесты, так чтобы работа ускорилась.
В любом случае? Знаешь, тут я даже не сомневаюсь в том, что это не соответствует действительности.
Вобщем, я конечно понимаю, что любого можно обвинить в неумении и криворукости. Только вот чего стоит технология, чтобы пользоваться которой нужно знать какие то эзотерические таинства?
M>Да нет, честно говоря не заставляет, потому что информации мало. Какого проекта?
В среднем по проектам, которые приходилось конторе, в которой работает товарищ, тестировать. Контора, как ты уже наверное догадался, аутсорсит тестовые услуги.
M> Какими тестами?
Модульными в основном.
M>К 100%? Да легко — я думаю что в MS (чтобы недалеко ходить) на некоторых проектах намного больще.
Вот. Думаю не надо говорить, что подобные затраты приемлемы не для любых проектов и не для любых фирм?
... << RSDN@Home 1.2.0 alpha rev. 646 on Windows XP 5.1.2600.131072>>
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, DarkGray, Вы писали:
DG>>я ответил. DG>>могу ответить более определенно — не знаю.
E>Так по моему мнению получается, что вы навязываете пользователю выбор разработчика.
E>Давайте доведем ситуацию до маразма:
А зачем до маразма ? Критерий кажется совершенно ясен , если проверка оставленная в коде не ухудшит качество программы , значит оставить , иначе не оставлять.
Здравствуйте, FDSC, Вы писали:
FDS>То есть для этого нам нужна уже готовая правильно работающая программа. Такие ЮТ могут найти ошибку только при изменении программы, но не при её первичной отладке. Надеюсь, это очевидно.
Гм. А как ты получаешь правильно работающую программу? Я вот обычно запускаю ее и смотрю на результат. Частенько в первый раз запускаю под дебаггером, чтобы убедиться, что алгоритм работает именно так, как я предусмотрел. Значительно реже я включаю трассировку.
Так что предложенный способ сам по себе мне очень нравится:
1. Пишем первичную версию, запускаем ее на каких-нибудь тестовых данных и смотрим в output. Если нас не устраивает этот output, мы правим программу. Повторяем до полного удовлетворения . (Обращаю внимание, что на этой фазе output педантично вычитывается). Коммит.
2. Обнаружив некоторый баг, придумываем новый набор входных данных, на которых он воспроизводится. Чиним код, чтобы и в этом случае получался корректный output #2. Простым сранвненим убеждаемся, что output #1 не сломался. Если оказывается, что новый результат тоже корректен (например, мы немного подправили условия задачи, или где-то нам неважен порядок вывода), то мы коммитим новый output #1.
Смысл замечательный — нам не надо отдельно описывать корректные результаты. Мы всего лишь фиксируем поведение программы на некоторый момент времени. Это может даже быть неправильное поведение. Но это позволяет отловить регрессию, а она и есть бич всех изменений. У нас нет точной статистики, но интуитивно все более значительная часть времени уходит на отлов именно регрессионных багов.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, mbergal, Вы писали:
AVK>Да, но как быть с TDD, предписывающим начинать проектирование с тестов? Что, писать по новой новый набор тестов при каждом редизайне?
За всех не скажу, но я пишу. Не всегда конечно UT в идеальном смысле (когда тестируется модуль совсем отдельно от других — но это другая тема). Вот что я не делаю, так это я часто сначала переписываю код а потом подписываю тесты (наверное в разрез с принципами TDD). Но потом тесты приписываю.
AVK>Это ж застрелиться просто! Писать тесты после того, как редизайн станет маловероятным в ближайшее время? Но это идет в разрез с принципами TDD.
Можно и так — это часть testing strategy.
[...]
M>>Но без знания конкретного случая рецепты давать сложно: какова стоимость написания теста,
AVK>Тебе в чем, в шекелях?
Мне было бы интересно узнать хотя бы субъективную оценку — для типичного модуля в проекте, сколько в результате имееем тестов и сколько времени тратиться на разработку среднего теста (в часах) — желательно сколько на дизайн и сколько на реализацию и показать типичный тест конечно.
M>> Какая test strategy (что и как мы будем тестировать,
AVK>Разрабатываемый продукт при помощи модульного тестирования.
Это не кажется мне хорошей test-strategy. Все будем так тестировать? И GUI? Все контуры продукта по 100% test coverage?
AVK>Здесь о UT вобще то топик. С функциональным тестированием все просто — оно должно быть. От него не уйдешь никаким боком.
А уже сошлись на том что такое UT? А то ветка большая, вроде я много прочел, но может что пропустил? Вот если мой тест не"exercises a single class in isolation of all others.", то эта ветка не о нем?
M>>как делается test coverage analysis и какая policy на изменение покрытия.
[...]
M>>Да нет, честно говоря не заставляет, потому что информации мало. Какого проекта?
AVK>В среднем по проектам, которые приходилось конторе, в которой работает товарищ, тестировать. Контора, как ты уже наверное догадался, аутсорсит тестовые услуги.
Нет — не догадался.
[...]
M>>К 100%? Да легко — я думаю что в MS (чтобы недалеко ходить) на некоторых проектах намного больще.
AVK>Вот. Думаю не надо говорить, что подобные затраты приемлемы не для любых проектов и не для любых фирм?
Наверное, я за все компании отвечать не берусь. У нас это наверное было бы чересчур, но не очень намного, если так по простому посчитать — 1 SDET на 1 SDE — это значит что минимум 100% стоимости разработки это тестирование.
Здравствуйте, WolfHound, Вы писали: WH>Я вобще не адепт TDD и мне нужны тесты не для того чтобы проверить корректность программы, а для того чтобы они показали что что-то изменилось.
Слушай, а как ты отличаешь настоящие изменения от таймстэмпов? У меня TortoiseSVN меняет иконку у всех перезаписанных файлов, даже если контент совсем не изменился.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, minorlogic, Вы писали:
M>А зачем до маразма ? Критерий кажется совершенно ясен , если проверка оставленная в коде не ухудшит качество программы , значит оставить , иначе не оставлять.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>>... о срочных проектах. GZ>Тута есть еще одна штука. Если брать классические процессы, и это не система сделанная на коленке, то обычно действует правило 40-20-40, где 40 процентов времени занимет постановка, 20 программирование, и 40 процентов тестирование и отладка. Юнит-тесты могут сократить последнюю цифру.
Ты забыл кое о чем. Кроме того что они могут уменьшить последнюю цифру, они могут увеличить вторую и увеличить третью (тесты ведь тоже надо отлаживать).
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, WolfHound, Вы писали: WH>>Я вобще не адепт TDD и мне нужны тесты не для того чтобы проверить корректность программы, а для того чтобы они показали что что-то изменилось. S>Слушай, а как ты отличаешь настоящие изменения от таймстэмпов? У меня TortoiseSVN меняет иконку у всех перезаписанных файлов, даже если контент совсем не изменился.
Кстати да, интересно. У меня TortoiseSVN то же так делает (вчера проверил)
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, FDSC, Вы писали:
FDS>>То есть для этого нам нужна уже готовая правильно работающая программа. Такие ЮТ могут найти ошибку только при изменении программы, но не при её первичной отладке. Надеюсь, это очевидно. S>Гм. А как ты получаешь правильно работающую программу? Я вот обычно запускаю ее и смотрю на результат. Частенько в первый раз запускаю под дебаггером, чтобы убедиться, что алгоритм работает именно так, как я предусмотрел. Значительно реже я включаю трассировку. S>Так что предложенный способ сам по себе мне очень нравится: S>1. Пишем первичную версию, запускаем ее на каких-нибудь тестовых данных и смотрим в output. Если нас не устраивает этот output, мы правим программу. Повторяем до полного удовлетворения . (Обращаю внимание, что на этой фазе output педантично вычитывается). Коммит. S>2. Обнаружив некоторый баг, придумываем новый набор входных данных, на которых он воспроизводится. Чиним код, чтобы и в этом случае получался корректный output #2. Простым сранвненим убеждаемся, что output #1 не сломался. Если оказывается, что новый результат тоже корректен (например, мы немного подправили условия задачи, или где-то нам неважен порядок вывода), то мы коммитим новый output #1.
S>Смысл замечательный — нам не надо отдельно описывать корректные результаты. Мы всего лишь фиксируем поведение программы на некоторый момент времени. Это может даже быть неправильное поведение. Но это позволяет отловить регрессию, а она и есть бич всех изменений. У нас нет точной статистики, но интуитивно все более значительная часть времени уходит на отлов именно регрессионных багов.
Да я не спорю. Просто у человека всё слишком легко получалось по его словам.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, FDSC, Вы писали:
FDS>>Ну дак, опят же, может разработчик не strlen проверяет, а сразу целый набор функций.
IT>Ты бы проверял strlen в отдельности или в купе с целым набором функций?
Лично я практически всегда проверяю сразу комплекс функций. По одной мне всегда лень...
P.S. Тем более что я иногда просто не в состоянии понять, какой результат отдельной функции правильный, а какой нет.
M>>>К 100%? Да легко — я думаю что в MS (чтобы недалеко ходить) на некоторых проектах намного больще.
AVK>>Вот. Думаю не надо говорить, что подобные затраты приемлемы не для любых проектов и не для любых фирм?
M>Наверное, я за все компании отвечать не берусь. У нас это наверное было бы чересчур, но не очень намного, если так по простому посчитать — 1 SDET на 1 SDE — это значит что минимум 100% стоимости разработки это тестирование.
Я понимаю, что в пылу сражения забыли про то, что стоимость разработки ПО есть сумма не только стоимости кодирования и тестирования. Но вот что тестирование составляет 100% всей стоимости — это мне понравилось. Наверное, речь шла о 50%? Т.е. стоимость кодирования == стоимость тестирования
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, Sinclair, Вы писали:
S>>Здравствуйте, WolfHound, Вы писали: WH>>>Я вобще не адепт TDD и мне нужны тесты не для того чтобы проверить корректность программы, а для того чтобы они показали что что-то изменилось. S>>Слушай, а как ты отличаешь настоящие изменения от таймстэмпов? У меня TortoiseSVN меняет иконку у всех перезаписанных файлов, даже если контент совсем не изменился.
FDS>Кстати да, интересно. У меня TortoiseSVN то же так делает (вчера проверил)
— межкоммитную разработку (так как ждя приёмки эталонов их не надо коммитить)
— выборочный запуск тестов (только тех которые нужны в данный момент для отладки — проблемных)
— быстрый вывод и эталона и результата в том числе и в броузере как документа
— возможность встраивания в систему CruiseControl-я специальной консольной утилиты
кароче мне нужен квалифицированный feedback и контрибуторы!
DG>Возьмем ранее упоминавшийся графический движок — если он будет для каждого 100-го кадра в background-е проверять правильность вывода, через тот же более простой, но более медленный алгоритм, то ничего страшного не случится.
Аналогия придумалась. Допустим, в managed языках (Java, C#, Nemerle, Python, Ruby, ...) корректность индекса при обращении к элементу массива проверяется не при каждом обращении, а только при каждом сотом.
Какой смысл проверять что-то эпизодически и случайным образом, имхо, либо должны быть постоянные проверки, либо их не должно быть вовсе. А в противном случае получается стрельба по мухам в темноте в темной комнате наугад.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
AndrewVK wrote: > C>Как раз большая часть ошибок происходит из-за того, что свежий код > C>ломает другой код. > Крайне спорное утверждение. Я бы сказал, что обилие подобных ошибок > свидетельствует о высокой связности архитектуры.
Добавлю: нетривиальных ошибок.
И как раз в слабосвязанной архитектуре их искать сложнее всего — как раз
из-за слабых связей между модулями.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, DarkGray, Вы писали:
DG>>Возьмем ранее упоминавшийся графический движок — если он будет для каждого 100-го кадра в background-е проверять правильность вывода, через тот же более простой, но более медленный алгоритм, то ничего страшного не случится.
E>Аналогия придумалась. Допустим, в managed языках (Java, C#, Nemerle, Python, Ruby, ...) корректность индекса при обращении к элементу массива проверяется не при каждом обращении, а только при каждом сотом.
E>Какой смысл проверять что-то эпизодически и случайным образом, имхо, либо должны быть постоянные проверки, либо их не должно быть вовсе. А в противном случае получается стрельба по мухам в темноте в темной комнате наугад.
E>)
В данном случае — наугад. А где-то, возможно, ошибки идут очередями (у АК )
Здравствуйте, Sinclair, Вы писали:
S>Слушай, а как ты отличаешь настоящие изменения от таймстэмпов? У меня TortoiseSVN меняет иконку у всех перезаписанных файлов, даже если контент совсем не изменился.
У меня стоит тортилка (ща все упадут) 1.1.3
Она меняет иконку только если файл действительно изменился. Болие того иконка меняется обратно если файл сново стал эталонным.
К тому же всегда можно нажать check for modifications или вобще сразу commit.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Cyberax, Вы писали:
C>AndrewVK wrote: >> C>Как раз большая часть ошибок происходит из-за того, что свежий код >> C>ломает другой код. >> Крайне спорное утверждение. Я бы сказал, что обилие подобных ошибок >> свидетельствует о высокой связности архитектуры. C>Добавлю: нетривиальных ошибок.
C>И как раз в слабосвязанной архитектуре их искать сложнее всего — как раз C>из-за слабых связей между модулями.
>> Крайне спорное утверждение. Я бы сказал, что обилие подобных ошибок >> свидетельствует о высокой связности архитектуры.
C>И как раз в слабосвязанной архитектуре их искать сложнее всего — как раз C>из-за слабых связей между модулями.
Т.е. под ЮТ нужно специально писать сильносвязанную архитектуру в которой все падает при малейшем движении Зашибись
crazz wrote: >> > Крайне спорное утверждение. Я бы сказал, что обилие подобных ошибок >> > свидетельствует о высокой связности архитектуры. > C>И как раз в слабосвязанной архитектуре их искать сложнее всего — как раз > C>из-за слабых связей между модулями. > Т.е. под ЮТ нужно специально писать сильносвязанную архитектуру в > которой все падает при малейшем движении
С чего бы? Просто ЮТ помогают тестировать неявные связи, которые все
равно возникают, как бы не пытались разделить модули.
Здравствуйте, FDSC, Вы писали:
FDS>Это не так. Допустим, на каждый модуль у вас 10 ЮТ тестов. У меня 10 КТ тестов на всю программу. У вас каждый модуль отрабатывает в ЮТ по 10 раз и у меня столько же.
Даже 1000 ЮТ может пройти быстрее чем один 1 КТ, только потому, что там не нужно будет лазить в БД и поднимать несколько сервисов для удалённого общения между ними.
FDS>Другой вопрос, если вы поменяли один модуль и только его оттестировали — то да, вы правы, но лично для меня это никогда не было критичным. А вот то, что после изменения одного модуля всё равно нужно провести КТ, на всякий случай, это для меня непреложная истина.
Это так. Но до того момента когда нужно запускать КТ нужно еще дожить
ANS>>2. Что касается пользы от ЮТ. У нас (j2ee) при разработке ЮТ валятся часто, то там то сям (привет статической типизации). До введения ЮТ часто были ситуации, что народ просто боялся обновлятся из VCS. Потому, что фиг потом поймёш это ты всё поломал, или кто другой. Потом всё это с огромным гимором мержилось. В общем, ЮТ+CruiseControl это есть хорошо.
FDS>Бранчи надо делать
Всё равно смерджить всё это в конце может быть сложно
FDS>Ну насколько у нас большая разница в подходах к разработке ПО! Без тестов я понимаю что делает код, с тестами — считаю что работают правильно отдельные модули, значит и в целом всё правильно . Поэтому мне ЮТ как раз мешают понимать, что делает программа (да на это уже и времени не остаётся)
ЮТ просто заставляет писать модульную программу. Это есть огромный плюс. Даже если не писать ЮТ можно представлять что ты их пишеш и проектировать соответсвенно.
Здравствуйте, WolfHound, Вы писали:
FDS>>Если вы согласны с тем, что это нужно сделать целый один раз, т.е. получить правильную часть программы сначала без ЮТ или вручную получить правильный результат, то да. Мы и говорим, что сначала нам нужно тестировать всё в ручную, а потом использовать ЮТ, ПОСЛЕ ручного тестирования, фактически, как регрессионный тест. Данный пункт и призван вам показать этот недостаток вами же предложенного варианта со статическими входными данными: программа должна быть написана сначала без ЮТ, с помощью ручного тестирования.
ЮТ помогают не только при наличии эталонного результата. Они могут проконтролировать обращение к другим модулям при определённых условиях. То есть в случае А идёт обращение к одному модулю, а в случае Б к другому. Плюс "эталонный результат" это может быть константа (из некого набора констант). Или факт выброса исключения. Опять же, чтобы проверить добавился ли элемент в коллекцию при определённых условиях не нужно ручками ничего тестировать. И т.д.
Здравствуйте, minorlogic, Вы писали:
M>Категорически не согласен. M>Представим модуль ThreadPool у которого есть только функция add_task(). Как посредством только этого интерфейса можно оттестировать логику работы с потоками , как менеджер потоков реагирует на различные события , как увеличивает — уменьшает кво работающих потоков и т.п ? M>Расскажите плиз , как бы вы тестировали такой модуль. ?
OK. Входные параметры — количество заказанных потоков, выходные наличие потоков в конкретный момент времени. В данном случае у нас два способа. 1 — способ, добавить свойсва возращающие текущее состояние. Такие свойства обычно сделать очень быстро, так как внутри они содержатся. 2 — способ, на основе логгирования/trace. Я бы поостерегся делать серьезное приложение, если из подобных модулей нельзя снять состояние в момент ошибки(которое вероятнее всего даже не связано с данным модулем). Такой лог в дальнейшем должен отсылаться производителю, то бишь нам. И можно анализировать данный лог(можно даже через regexp). Хотя первый способ делается легче.
Теперь по самому тестированию. Первое конечно то, тестируется то что он сожрал один поток. Это можно сделать до реализации. Второй — работа с двумя потоками. И третье — работа с максимальным количеством потоков. И четвертое, если у нас при превышении потоков должна выводиться ошибка — тест на получение корректной ошибки. Все четыре ситуации отрабатывают, можно считать что add_task работает. И если кто-то, как-то напакостил, мы всегда это можем проверить. То же самое по остальным ситуациям. Проверяем что работает. И проверяем при граничных условиях. Алгоритм проверки прост, и главное автоматизирован. Через интерфейсы многие граничные ситуации создать нельзя, а программно можно. Хотя иногда и программно — невозможно проверить. Ну соответвенно, разделяем по категориям. Проверка на границы нужна только когда нужно подтверждение о том что все точно работает. Она по времени достаточно долгая. И она запускается реже чем тупая проверка о работоспособности модуля.
M>Под "пользователями" я подразумевал , ваших колег которые будут работать в процессе интеграции с вашим модулем , тестеры , и бета тестеры.
Я бы поостерегся отдавать тестарам и бета-тестерам дебугнутую версию. Они ведь тестируют удобство и производительность также. И остальные нефункциональные требования.
M>>>3. Встроенность в код. M>>>Вероятно многие знают , насколько это геморойно , изменяя код ,переписывать и юнит тесты. Это может просто ЗЛИТЬ, чувство потерянного впустую времени. GZ>>Не изменяя код. А изменяя интерфейс или функциональность. Это очень разные вещи. К тому же, обычно кто реализует, тот и пишет тест.
M>Я уже говорил , и повторю что оттестировать изнутри можно намного эфективнее. Считаю что в этом вопросе вы не правы.
Мы изнутри можем легко оттестировать реализацию. Точнее только ту реализацию, которую можно создать текущим неэмулируемым функционалом в короткие сроки. И при этом, если у тебя реализация меняется, меняются и сами тесты. В случае UT — тестируется интерфейс.
M>А подхол с СК , вы не включили в этот перечень ? Мне кажется существует намного больше подходов чем два, и не вижу причин почему СК может не применяться везде где это можно (но не более того).
Применятся оно конечно может где угодно. Но вот делать на нем что-то серьезное я бы поостерегся(по вышеперечисленным причинам). Это должна быть сильно специфичная вещь.
M>Ну бывает и такое , а какое отношение это имеет к предыдущему разговору. Я кстати знаю массу проектов где релизная сборка просто не нужна , нет никаких тербований по производительности ... И даже слышал что некоторые проекты вообще релизной не пользуются.
Ага. Я тоже знаю примеры, когда к дебаг проекту внезапно понадобился присобачить релизную dll. С учетом разности работы с аллокацией памяти. Дебаги это совсем не есть карашо.
M> Преимущества я писал , вы не согласны. Мне реально хочется узнать почему , и если можно с маааленьким примером. Я не уверен в своей правоте на 100% , и поэтому хочется послушать коментарии по делу. Ваш пост пока один по делу , спасибо.
Вроде пример привел.
M>Текстовая строка кодируется определенным образом , потом обратной функцией декодируется. Обе функции внутри себя проверяют коректность кодирования через декодирование и наоборот , и если произошла ошибка — функция возврашаерт ошибку. M>Это пример когда производительность меня совершенно на порядки меньше интересовала чем коректность. И прежде чем этот код пойдет к клиенту , я знаю что он проработает сотни тысяч раз в процессе разработки, но и в релизном варианте , пускай лучше код вернет ошибку и я буду о ней знать (с описанием) чем код будет работать неправильно у клиента и я не смогу даже примено идентифицировать баг.
Тут возникает следующий вопрос. А что вернется клиенту в случае ошибки? Если ему вернется что в строке 100 dubadu.cpp произошел assert, то звонков не оберешься. Если что-то случилось даже за долгий период, то юзверя звереют и начинают утверждать что не работает все(где как попадешься ). Вдруг вызывающий модуль сознательно создал эту ошибку(хоть это и нехорошо)? Поэтому любая ошибка должны быть глобально квалифицированна для всей группы разработчиков. Чтобы в случае чего они могли ее корректно обрабатывать. И вывод сообщения пользователю должен быть корректным, чтобы он не пугался.
Здравствуйте, AndrewVK, Вы писали:
AVK>P.S. По свидетельству знакомых, занимающихся тестированием профессионально, долго и успешно, стоимость хорошего покрытия тестами проекта составляет от 25 до 40 процентов от стоимости разработки того, что тестируют, в случае, если проект неплохо подходит для модульного тестирования. Если подходит плохо, то цифра может быть и 100%.
Что подразумевается под стоимостью разработки. Разработка полностью, или только кодирование. AVK>Циферки заставляют задуматься, не правда ли?
Бесплатный сыр в мышеловках. За все надо платить.
Здравствуйте, crazz, Вы писали:
C>Ты забыл кое о чем. Кроме того что они могут уменьшить последнюю цифру, они могут увеличить вторую и увеличить третью (тесты ведь тоже надо отлаживать).
Вторую да, третью нет.
Здравствуйте, WolfHound, Вы писали:
WH>Я вобще не адепт TDD и мне нужны тесты не для того чтобы проверить корректность программы, а для того чтобы они показали что что-то изменилось.
WH>Я в ручную отлаживаю систему и паралельно делаю дамп решения. WH>Далие этот дамп будет сравниваться с дампами после изменения системы. WH>Если дампы не совпали то начинаем разбиратся что произошло.
afaik это называется регресное тестирование. Оно показывает наличие регреса в системе (всё раньше работало, а теперь нет). Врядли оно имеет хоть какое то отношение к TDD (кроме слова "тест" в названии), но, подозреваю, что может иметь отношение к ЮТ, если котролируется только один модуль, а не вся система в целом.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Здесь программирование происходит в условиях перманентной нехватки времени. В таких условиях вопрос: "А где юнит-тесты?" звучит как издевательство. Очевидный ответ на этот вопрос: "А может вам ещё танец живота на столе станцевать?".
Везде свои условия. У нас сразу в 2-х проектах одной системы юнит тесты — это вообще единственная возможность запустить и отладить некий функционал, ибо есть асинхронно общающиеся участники системы, т.е. сложновато умудриться "проверить ручками", заставив пройти определенную ветку алгоритма. Поэтому используем всякие заглушки противоположной стороны как техническую базу для тестирования (для организаци возможности заведомо пройтись по определенным веткам алгоритмов). Практически это — "внешние" юнит-тесты.
LCR>>... о срочных проектах. GZ>Тута есть еще одна штука. Если брать классические процессы, и это не система сделанная на коленке, то обычно действует правило 40-20-40, где 40 процентов времени занимет постановка, 20 программирование, и 40 процентов тестирование и отладка. Юнит-тесты могут сократить последнюю цифру.
Если речь идет о типовых проектах, которые делаются пачками, то отношения немного не такие. Субъективно на мой взгляд, примерно 10-80-10. И юнит-тесты есть только для базового функционала наработанного фреймворка.
Здравствуйте, vdimas, Вы писали:
GZ>>Тута есть еще одна штука. Если брать классические процессы, и это не система сделанная на коленке, то обычно действует правило 40-20-40, где 40 процентов времени занимет постановка, 20 программирование, и 40 процентов тестирование и отладка. Юнит-тесты могут сократить последнюю цифру.
V>Если речь идет о типовых проектах, которые делаются пачками, то отношения немного не такие. Субъективно на мой взгляд, примерно 10-80-10. И юнит-тесты есть только для базового функционала наработанного фреймворка.
В данном случае Startup под ключ.
Здравствуйте, eao197, Вы писали:
E>Однако, влияние второго фактора можно снизить (к сожалению, только снизить, а не устранить), если создавать код изначально предназначенный для покрытия его unit-тестами. Например, я сейчас добавляю новую функциональность в C++ную DLL-ку. Причем модифицируются и добавляются классы, которые из этой DLL не экспортируются (т.е. снаружи не видны). Первоначально библиотека была написана так, что ее можно было проверить только на имитационном стенде, путем имитации реальной работы программы. Но сейчас я очень хочу иметь возможность контролировать ее с помощью unit-тестов. Выход в результате нашелся такой -- вынесение части функциональности из DLL в статические библиотеку. И создание unit-тестов, которые линкуются к этим LIB-ам. Т.е. появилась дополнительная сложность -- кроме решения задач самой библиотеки я еще вынужден придумывать, как же ее автоматом протестировать.
Нужное выделил. Таки только так можно адекватно тестировать C++-код, который требует окружения. Юнит-тесты в данном случае тестируют не DLL, а именно код. С моей точки зрения — все вполне корректно.
У нас в проекте в статическую либу вынесена не часть функциональности, а вообще вся функциональность, и юнит-тестам, соответственно, доступны все заголовки.
Здравствуйте, mbergal, Вы писали:
M>За всех не скажу, но я пишу.
Ну вот а у меня получается ерунда, потому что вместо работы с кодом я половину времени теряю на рефакторинг тестов. Результаты весьма плачевны.
M>Вот что я не делаю, так это я часто сначала переписываю код а потом подписываю тесты (наверное в разрез с принципами TDD). Но потом тесты приписываю.
Я что то не понял. Так ты все же до переделки тесты пишешь или после?
M>Можно и так — это часть testing strategy.
От того, что ты придумал красивый термин ничего, увы не поменялось.
AVK>>Тебе в чем, в шекелях?
M>Мне было бы интересно узнать хотя бы субъективную оценку — для типичного модуля в проекте,
Вот с этим я определиться не могу. Есть крупные модули, есть составляющие их мелкие, есть независимые мелкие. Для мелких число тестов от 1-2 до 20-25. Крупные как правило автоматически тестировать не получается ввиду завязки на окружение.
M> сколько в результате имееем тестов и сколько времени тратиться на разработку среднего теста (в часах) — желательно сколько на дизайн и сколько на реализацию и показать типичный тест конечно.
Такой метрики точно никто не вел. Сильно по разному в разных случаях. Единственное, львиная доля уходит, конечно, на дизайн.
M>>> Какая test strategy (что и как мы будем тестировать,
AVK>>Разрабатываемый продукт при помощи модульного тестирования.
M>Это не кажется мне хорошей test-strategy. Все будем так тестировать? И GUI?
Скажем так, GUI в той части, на которой я проводил эксперименты, просто нет.
M> Все контуры продукта по 100% test coverage?
Близко к тому, но при помощи специальных тулзов никто сей факт не контроллирует. Понимаешь, это в любом случае имеет мало отношения к описываемой мной проблеме. От того, что coverage станет лучше проблема только усилится.
AVK>>Здесь о UT вобще то топик. С функциональным тестированием все просто — оно должно быть. От него не уйдешь никаким боком.
M>А уже сошлись на том что такое UT? А то ветка большая, вроде я много прочел, но может что пропустил? Вот если мой тест не"exercises a single class in isolation of all others.", то эта ветка не о нем?
Интересный у тебя подход. Тебе лень прочесть ветку на русском, а мне предлагаешь читать чей то блог на неродном мне языке.
Здравствуйте, FDSC, Вы писали:
FDS>Я понимаю, что в пылу сражения забыли про то, что стоимость разработки ПО есть сумма не только стоимости кодирования и тестирования. Но вот что тестирование составляет 100% всей стоимости — это мне понравилось. Наверное, речь шла о 50%? Т.е. стоимость кодирования == стоимость тестирования
Когда я циферки приводил, я ясно написал
процентов от стоимости разработки того, что тестируют
Кодирование тут не при чем, потому что в стоимость разработки входит и работа аналитиков, и работа архитекторов. Т.е. это проценты от стоимости проекта, если бы в нем вобще модульное тестирование не применялось.
Здравствуйте, GlebZ, Вы писали:
GZ>Что подразумевается под стоимостью разработки. Разработка полностью, или только кодирование.
Я вроде ясно выразился. Разработка полностью без собственно тестирования.
AVK>>Циферки заставляют задуматься, не правда ли? GZ>Бесплатный сыр в мышеловках. За все надо платить.
Вопрос в том, что не всегда плата соответствует результату.
Здравствуйте, FDSC, Вы писали:
IT>>Ты бы проверял strlen в отдельности или в купе с целым набором функций?
FDS>Лично я практически всегда проверяю сразу комплекс функций. По одной мне всегда лень...
Вот, вот. А потом, когда через пол года ловишь багу, думаешь про себя: вот урод, ну почему нельзя было написать на один тест больше.
FDS>P.S. Тем более что я иногда просто не в состоянии понять, какой результат отдельной функции правильный, а какой нет.
Ну как бы strlen("Oops") должен вернуть sizeof("Oops')-1. Разве нет?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, minorlogic, Вы писали:
C>>Ыыы... Ну вообще-то юнит-тесты — это как раз и есть наборы небольших C>>тестов, часто встраиваемых в сам код модуля (в Питоне, например).
M>Мне кто то пару постов доказывал что это не так .
Тебе доказывали, что ассерты — это не то же самое, что юнит-тесты.
А в общем случае юнит-тесты тоже могут быть интегрированы в код модуля — но вызов их будет отдельный, а не в процессе обычного выполнения программы, как в случае ассертов.
Здравствуйте, AndrewVK, Вы писали:
AVK>Вопрос в том, что не всегда плата соответствует результату.
Все таки я немного не врубился. Допустим взята на вооружение TDD. Фактически с помощью unit-тестов прогоняется архитектура проекта(я не беру в учет XP). Фактически с помощью тестов определяется реальные интерфейсы приложения. И причем тут ихняя фирма? Они что проектируют? Или просто занимаются тем, что покрывают тестами уже готовые решения. В первом случае, накладные расходы должны быть меньше. Хотя до 30 процентов — взамен текстового документирования/проектирования я бы стерпел. Но если делать после, большая часть смысла тестов просто испаряется.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, crazz, Вы писали:
C>>Ты забыл кое о чем. Кроме того что они могут уменьшить последнюю цифру, они могут увеличить вторую и увеличить третью (тесты ведь тоже надо отлаживать). GZ>Вторую да, третью нет.
Здравствуйте, crazz, Вы писали:
C>Т.е. ты тесты не отлаживаешь?
Не понял??? Зачем тебе на этапе стабилизации отладка модульных тестов? В 99 процентов случаев на данном этапе, ты поправляешь реализацию особо не трогая функциональность как таковую.
Здравствуйте, GlebZ, Вы писали:
AVK>>Вопрос в том, что не всегда плата соответствует результату. GZ>Все таки я немного не врубился. Допустим взята на вооружение TDD. Фактически с помощью unit-тестов прогоняется архитектура проекта(я не беру в учет XP). Фактически с помощью тестов определяется реальные интерфейсы приложения. И причем тут ихняя фирма?
Не при чем. Я не зря разговоры об этой фирме в постскрптум вынес.
GZ> Они что проектируют? Или просто занимаются тем, что покрывают тестами уже готовые решения.
Второе, но не обязательно готовоые. Они участвуют в процессе разработки.
GZ> В первом случае, накладные расходы должны быть меньше.
Скорее наоборот больше — менее профессиональные работники, больше изменений.
GZ>Но если делать после, большая часть смысла тестов просто испаряется.
Главный смысл тестов — проверка решения. Она никуда не денется.
Угу, в проекте на C# вначале тоже активно взялись за юнит-тесты, но потом затраты на сопровождение их вместе с изменениями кода стали неприемлимыми. Забросили нафик. Итого, первые версии (для внутреннего тестирования) шли по большей части без покрытия юнит-тестами. Ближе к выпуску стали покрывать наиболее ответственные моменты юнит-тестами. Кроме того, к концу картинка была намного ясней, т.е. приоритеты покрытия юнит-тестами распределялись вполне осмысленно.
В другом проекте (С++) было наоборот, сами юнит-тесты были единственной возможностью для запуска и отладки кода, пока не было готово "все остальное".
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, FDSC, Вы писали:
FDS>>Это не так. Допустим, на каждый модуль у вас 10 ЮТ тестов. У меня 10 КТ тестов на всю программу. У вас каждый модуль отрабатывает в ЮТ по 10 раз и у меня столько же.
ANS>Даже 1000 ЮТ может пройти быстрее чем один 1 КТ, только потому, что там не нужно будет лазить в БД и поднимать несколько сервисов для удалённого общения между ними.
Собственно, я уже сказал, что если запускать не все ЮТ — то быстрее. Ваш комментарий — частный случай. Так как при запуске всех ЮТ всё равно кто-то в БД полезет
FDS>>Другой вопрос, если вы поменяли один модуль и только его оттестировали — то да, вы правы, но лично для меня это никогда не было критичным. А вот то, что после изменения одного модуля всё равно нужно провести КТ, на всякий случай, это для меня непреложная истина.
ANS>Это так. Но до того момента когда нужно запускать КТ нужно еще дожить
Не так долго этого ждать. КТ не обязательно должен всю программу тестировать. И вообще, он может тестировать незаконченную версию программы. Если соотв. образом поставить разработку, то КТ можно будет запускать раньше ЮТ, просто потому что ЮТ ещё надо будет написать
ANS>>>2. Что касается пользы от ЮТ. У нас (j2ee) при разработке ЮТ валятся часто, то там то сям (привет статической типизации). До введения ЮТ часто были ситуации, что народ просто боялся обновлятся из VCS. Потому, что фиг потом поймёш это ты всё поломал, или кто другой. Потом всё это с огромным гимором мержилось. В общем, ЮТ+CruiseControl это есть хорошо.
FDS>>Бранчи надо делать
ANS>Всё равно смерджить всё это в конце может быть сложно
Согласен полностью.
FDS>>Ну насколько у нас большая разница в подходах к разработке ПО! Без тестов я понимаю что делает код, с тестами — считаю что работают правильно отдельные модули, значит и в целом всё правильно . Поэтому мне ЮТ как раз мешают понимать, что делает программа (да на это уже и времени не остаётся)
ANS>ЮТ просто заставляет писать модульную программу. Это есть огромный плюс. Даже если не писать ЮТ можно представлять что ты их пишеш и проектировать соответсвенно.
Я всегда пишу "модульные" программы, но это не значит, что они приспособлены для ЮТ .
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, FDSC, Вы писали:
IT>>>Ты бы проверял strlen в отдельности или в купе с целым набором функций?
FDS>>Лично я практически всегда проверяю сразу комплекс функций. По одной мне всегда лень...
IT>Вот, вот. А потом, когда через пол года ловишь багу, думаешь про себя: вот урод, ну почему нельзя было написать на один тест больше.
Я пробовал писать ЮТ и на количество найденных ошибок они не повлияли (если не считать, что я вообще хуже программировал, когда надо было думать о ЮТ).
К тому же я обычно думаю про себя: "вот урод, нельзя было по понятнее написать и подумать перед тем как пишешь". А для того, что бы писать понятнее нужно время, для ЮТ тоже нужно время — нужно выбирать что-то.
FDS>>P.S. Тем более что я иногда просто не в состоянии понять, какой результат отдельной функции правильный, а какой нет.
IT>Ну как бы strlen("Oops") должен вернуть sizeof("Oops')-1. Разве нет?
Я не конкретно про эту функцию. Ведь можно проверять правильность построения сетевого графика или, скажем, правильность расчёта конструкции на прочность. Даже для того, что бы проверить правильность решения дифференциального уравнения уже нужно на кодирование ЮТ не меньше времени, чем на кодирование основного модуля.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, FDSC, Вы писали:
FDS>>Я понимаю, что в пылу сражения забыли про то, что стоимость разработки ПО есть сумма не только стоимости кодирования и тестирования. Но вот что тестирование составляет 100% всей стоимости — это мне понравилось. Наверное, речь шла о 50%? Т.е. стоимость кодирования == стоимость тестирования
AVK>Когда я циферки приводил, я ясно написал AVK>
процентов от стоимости разработки того, что тестируют
AVK>Кодирование тут не при чем, потому что в стоимость разработки входит и работа аналитиков, и работа архитекторов. Т.е. это проценты от стоимости проекта, если бы в нем вобще модульное тестирование не применялось.
Это некорректная оценка, так как стоимость разработки тогда включает в себя издержки на не-ЮТ тестирование, которые зависят от того, используем мы ЮТ или нет. Тогда уж надо "процент от стоимости разработки без учёта всех фаз тестирования".
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, mbergal, Вы писали:
M>> сколько в результате имееем тестов и сколько времени тратиться на разработку среднего теста (в часах) — желательно сколько на дизайн и сколько на реализацию и показать типичный тест конечно.
AVK>Такой метрики точно никто не вел. Сильно по разному в разных случаях. Единственное, львиная доля уходит, конечно, на дизайн.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>>Здесь программирование происходит в условиях перманентной нехватки времени. В таких условиях вопрос: "А где юнит-тесты?" звучит как издевательство. Очевидный ответ на этот вопрос: "А может вам ещё танец живота на столе станцевать?".
V>Везде свои условия. У нас сразу в 2-х проектах одной системы юнит тесты — это вообще единственная возможность запустить и отладить некий функционал, ибо есть асинхронно общающиеся участники системы, т.е. сложновато умудриться "проверить ручками", заставив пройти определенную ветку алгоритма. Поэтому используем всякие заглушки противоположной стороны как техническую базу для тестирования (для организаци возможности заведомо пройтись по определенным веткам алгоритмов). Практически это — "внешние" юнит-тесты.
А они точно "юнит", или они всё таки как заглушки на части системы стоят: тогда это уже не совсем ЮТ?
Здравствуйте, FDSC, Вы писали:
IT>>Вот, вот. А потом, когда через пол года ловишь багу, думаешь про себя: вот урод, ну почему нельзя было написать на один тест больше.
FDS>Я пробовал писать ЮТ и на количество найденных ошибок они не повлияли (если не считать, что я вообще хуже программировал, когда надо было думать о ЮТ).
ЮТ не влияют на количество найденных ошибок. Они влияют на количество не сделанных ошибок.
FDS>К тому же я обычно думаю про себя: "вот урод, нельзя было по понятнее написать и подумать перед тем как пишешь". А для того, что бы писать понятнее нужно время, для ЮТ тоже нужно время — нужно выбирать что-то.
Я говорю о ситуации, когда в процессе разработки тесты всё равно надо писать. В случае strlen тест всё равно нужно написать, или ты с этим не согласен?
FDS>>>P.S. Тем более что я иногда просто не в состоянии понять, какой результат отдельной функции правильный, а какой нет.
Понятно. Ты примеряешь всё на свой опыт, обобщаешь и делаешь выводы. Это — не правильно. У меня есть задачи, где я не использую ЮТ по тем же причинам, о которых говоришь ты. А есть задачи, где без ЮТ эти задачи никогда не вышли бы из состояния беты. А если бы и вышли, то не на долго.
IT>>Ну как бы strlen("Oops") должен вернуть sizeof("Oops')-1. Разве нет?
FDS>Я не конкретно про эту функцию.
А я конкретно про эту, о чём и сказал в своём первом посте.
FDS>Ведь можно проверять правильность построения сетевого графика или, скажем, правильность расчёта конструкции на прочность. Даже для того, что бы проверить правильность решения дифференциального уравнения уже нужно на кодирование ЮТ не меньше времени, чем на кодирование основного модуля.
Совершенно верно. Есть задачи, где ЮТ требуют либо фактически удвоения времени разработки, либо кардинального изменения процесса разработки и подстраивания под ЮТ архитектуры, либо и того и другого вместе. Среди таких задач можно ещё выделить задачи UI, где специально для возможности тестирования нужно максимально абстрагировать сам UI от логики, что в большинстве случаев не даёт никаких бенефитов и явно попахивает антипаттерном Poltergeists. Другой пример — приложения ориентированные на работу с БД. Здесь проблема даже не в написании ЮТ, а в тщательной подготовки данных для них.
Но это всё абсолютно не значит, что нет задач, на которых ЮТ рулит. Таких задач полно, и ЮТ в них как нельзя кстати.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
FDS>>К тому же я обычно думаю про себя: "вот урод, нельзя было по понятнее написать и подумать перед тем как пишешь". А для того, что бы писать понятнее нужно время, для ЮТ тоже нужно время — нужно выбирать что-то.
IT>Я говорю о ситуации, когда в процессе разработки тесты всё равно надо писать. В случае strlen тест всё равно нужно написать, или ты с этим не согласен?
Нет. Я согласен с тем, что нужно написать тест на функцию, которая эту lstrlen будет использовать.
FDS>>Ведь можно проверять правильность построения сетевого графика или, скажем, правильность расчёта конструкции на прочность. Даже для того, что бы проверить правильность решения дифференциального уравнения уже нужно на кодирование ЮТ не меньше времени, чем на кодирование основного модуля.
IT>Совершенно верно. Есть задачи, где ЮТ требуют либо фактически удвоения времени разработки, либо кардинального изменения процесса разработки и подстраивания под ЮТ архитектуры, либо и того и другого вместе. Среди таких задач можно ещё выделить задачи UI, где специально для возможности тестирования нужно максимально абстрагировать сам UI от логики, что в большинстве случаев не даёт никаких бенефитов и явно попахивает антипаттерном Poltergeists. Другой пример — приложения ориентированные на работу с БД. Здесь проблема даже не в написании ЮТ, а в тщательной подготовки данных для них.
IT>Но это всё абсолютно не значит, что нет задач, на которых ЮТ рулит. Таких задач полно, и ЮТ в них как нельзя кстати.
Можно пример. Именно задачи, а не функция strlen. Скажем, численное интегрирование — это уже задача. (вообще я близок к пониманию того, что вы говорите...)
Здравствуйте, FDSC, Вы писали: FDS>НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в графе?
Написать простой — переборный вариант и сранивать результаты на случайных тестах
Здравствуйте, little_alex, Вы писали:
_>Здравствуйте, FDSC, Вы писали: FDS>>НУ, хорошо. А как протестировать алгоритм нахождения кратчайшего пути в графе? _>Написать простой — переборный вариант и сранивать результаты на случайных тестах
1. Написать такой вариант, извините, сложнее чем сам алгоритм
2. Ошибки в алгоритмах часто проявляются именно на сложных данных, а такой тест будет работать недопустимо долго.
3. Не всегда всё так просто.
Здравствуйте, FDSC, Вы писали:
AVK>>Такой метрики точно никто не вел. Сильно по разному в разных случаях. Единственное, львиная доля уходит, конечно, на дизайн.
FDS>А показать типичный тест?
Здравствуйте, FDSC, Вы писали:
IT>>Но это всё абсолютно не значит, что нет задач, на которых ЮТ рулит. Таких задач полно, и ЮТ в них как нельзя кстати.
FDS>Можно пример. Именно задачи, а не функция strlen. Скажем, численное интегрирование — это уже задача. (вообще я близок к пониманию того, что вы говорите...)
Например, написание компиляторов. Добавление новой фичи, может не показаться ломающей предыдущий код, но на деле оказаться. Всевозможные библиотеки, например, .NET framework. Я во всю использую ЮТ в bltoolkit. Ситуаций когда новое изменение ломало старый код было предостаточно. Ценность ЮТ как раз в том, что они позволяют это распознать на самых ранних стадиях, т.к. в процессе работы на библиотекой для проверки и отладки кода я полагаюсь не на свою интуицию, а на зелёненькие лампочки.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, FDSC, Вы писали:
IT>>>Но это всё абсолютно не значит, что нет задач, на которых ЮТ рулит. Таких задач полно, и ЮТ в них как нельзя кстати.
FDS>>Можно пример. Именно задачи, а не функция strlen. Скажем, численное интегрирование — это уже задача. (вообще я близок к пониманию того, что вы говорите...)
IT>Например, написание компиляторов. Добавление новой фичи, может не показаться ломающей предыдущий код, но на деле оказаться. Всевозможные библиотеки, например, .NET framework. Я во всю использую ЮТ в bltoolkit. Ситуаций когда новое изменение ломало старый код было предостаточно. Ценность ЮТ как раз в том, что они позволяют это распознать на самых ранних стадиях, т.к. в процессе работы на библиотекой для проверки и отладки кода я полагаюсь не на свою интуицию, а на зелёненькие лампочки.
Вот у меня и самый главный вопрос: почему вы полагаетесь на зелёненкие лампочки именно ЮТ. Т.е. зачем так мелко дробить тесты. Почему вы сделаете, грубо говоря, 20 тестов на один мой для того же компилятора: я сделаю один, который проверит сразу всё несколькими вариантами, а вы сделаете по несколько на класс. И, заметьте, нас обоих это удовлетворит. При этом при разработке вы будете добавлять ЮТ к модулям, а я буду добавлять новые тесты (или менять старые, что уже хуже) ко всей системе или крупным её частям.
Проще говоря, вопрос не в том, надо ли тестировать, а в том, насколько мелкие единицы тестировать. Я предлагаю тестировать относительно крупные единицы, вы — очень мелкие. Из-за чего такая разница, именно на примере компилятора?
Здравствуйте, FDSC, Вы писали:
FDS>Вот у меня и самый главный вопрос: почему вы полагаетесь на зелёненкие лампочки именно ЮТ.
Потому что это удобно. Запустил одну программу, она выполнила все тесты.
FDS>Т.е. зачем так мелко дробить тесты.
Я нигде не говорил про размеры дробления вообще. Юнит тесты могут использоваться от тестирования отдельных параметров метода, до больших сценариев. Размер дробления здесь не важен.
FDS> Почему вы сделаете, грубо говоря, 20 тестов на один мой для того же компилятора: я сделаю один, который проверит сразу всё несколькими вариантами, а вы сделаете по несколько на класс.
Потому что я делаю не весь компилятор/библиотеку сразу, а по частям. Сделал часть, потестировал, отладил, перешёл к следующей части. А тест остаётся, и служит гарантией того, что если мне придётся менять уже законченную часть, то это изменение не сломает задуманную ранее функциональность. Вот и всё. Очень просто и главное удобно, т.к. с написанием тестов совмещается процесс девелопмента. Т.е. для такого рода задач это не притянутая за уши из книжек модная технология, а вполне естественный процесс.
FDS>И, заметьте, нас обоих это удовлетворит. При этом при разработке вы будете добавлять ЮТ к модулям, а я буду добавлять новые тесты (или менять старые, что уже хуже) ко всей системе или крупным её частям.
Для ЮТ я имею отлаженный механизм и кучу тулов, в том числе встроенных в студию и находящихся всегда под ругой. А что такое твой "тест ко всей системе"?
FDS>Проще говоря, вопрос не в том, надо ли тестировать, а в том, насколько мелкие единицы тестировать. Я предлагаю тестировать относительно крупные единицы, вы — очень мелкие.
Я нигде не предлагал тестировать ни мелкие, ни крупные единицы. Это личное дело каждого. Я тестирую и сценарии и отдельные методы. Чего я не тестирую так это ветки кода. Тут действительно можно застрелиться.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, FDSC, Вы писали:
FDS>Здравствуйте, mbergal, Вы писали:
M>>>>К 100%? Да легко — я думаю что в MS (чтобы недалеко ходить) на некоторых проектах намного больще.
AVK>>>Вот. Думаю не надо говорить, что подобные затраты приемлемы не для любых проектов и не для любых фирм?
M>>Наверное, я за все компании отвечать не берусь. У нас это наверное было бы чересчур, но не очень намного, если так по простому посчитать — 1 SDET на 1 SDE — это значит что минимум 100% стоимости разработки это тестирование.
FDS>Я понимаю, что в пылу сражения забыли про то, что стоимость разработки ПО есть сумма не только стоимости кодирования и тестирования. Но вот что тестирование составляет 100% всей стоимости — это мне понравилось. Наверное, речь шла о 50%? Т.е. стоимость кодирования == стоимость тестирования
Это я криво сказал — надо было "все фазы тестирования — минимум 100% стоимости всей остальной разработки".
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, mbergal, Вы писали:
M>>Вот что я не делаю, так это я часто сначала переписываю код а потом подписываю тесты (наверное в разрез с принципами TDD). Но потом тесты приписываю.
AVK>Я что то не понял. Так ты все же до переделки тесты пишешь или после?
Часто после.
M>>Можно и так — это часть testing strategy.
AVK>От того, что ты придумал красивый термин ничего, увы не поменялось.
Я о ней думаю когда планирую реализации функциональности. Ее нужно продумывать как и нужно продумывать, например, дизайн подсистемы, зачастую и вместе с дизайном подсистемы. Именование помогает мне зафиксировать в голове, что это одна из областей нашей деятельности о которой нужно заботиться (для примера "refactoring" — удачное имя ускорило адаптацию).
[...]
AVK>Интересный у тебя подход. Тебе лень прочесть ветку на русском, а мне предлагаешь читать чей то блог на неродном мне языке.
Я прочитал. Только я вои не знаю как диагностировать следующие состояния:
1. Вопрос был обсужен.
2. Был кворум.
3. Были представлены варианты ответов.
4. Был достигнут консенсус по поводу максимально удовлетворяющего ответа(ов).
Так что Вы понимаете по UT, а что под функциональным тестом? и какие еще есть у Вас? А то вдруг мы о разном говорим?
Здравствуйте, IT, Вы писали:
FDS>>Т.е. зачем так мелко дробить тесты.
IT>Я нигде не говорил про размеры дробления вообще. Юнит тесты могут использоваться от тестирования отдельных параметров метода, до больших сценариев. Размер дробления здесь не важен.
Важен, так как ЮТ должен помочь локализовать ошибку, об этом уже в другой ветке спорили. Т.е. что ЮТ тестирует небольшой участок кода, а всё что под ним: то же тестируется, но другими ЮТ. А если это не так, то ЮТ уже не ЮТ, а просто автотесты.
FDS>> Почему вы сделаете, грубо говоря, 20 тестов на один мой для того же компилятора: я сделаю один, который проверит сразу всё несколькими вариантами, а вы сделаете по несколько на класс.
IT>Потому что я делаю не весь компилятор/библиотеку сразу, а по частям. Сделал часть, потестировал, отладил, перешёл к следующей части. А тест остаётся, и служит гарантией того, что если мне придётся менять уже законченную часть, то это изменение не сломает задуманную ранее функциональность. Вот и всё. Очень просто и главное удобно, т.к. с написанием тестов совмещается процесс девелопмента. Т.е. для такого рода задач это не притянутая за уши из книжек модная технология, а вполне естественный процесс.
Было бы интересно посмотреть на то, как делают библиотеки сразу, а не по частям . Тут я понял: просто я пренебрегаю регрессионными тестами на этапе кодирования базовой функциональности программы, а вы нет. Это, кстати, скорее всего потому, что у вас программы более объёмные по коду. Так что спасибо, когда дорасту учту, что иногда пренебрегаю тестами
FDS>>И, заметьте, нас обоих это удовлетворит. При этом при разработке вы будете добавлять ЮТ к модулям, а я буду добавлять новые тесты (или менять старые, что уже хуже) ко всей системе или крупным её частям.
IT>Для ЮТ я имею отлаженный механизм и кучу тулов, в том числе встроенных в студию и находящихся всегда под рукой. А что такое твой "тест ко всей системе"?
С технологической точки зрения реализации тестирования: тот же ЮТ. С точки зрения методики тестирования: программа, тестирующая верхний уровень функциональности программы при условии, что нижний уровень не протестирован никакими ЮТ. Вопрос как раз и заключался в том, зачем тестировать нижний уровень, если верхний всё-равно ошибку выдаст (а он выдаст...).
Глупый вопрос: а что в студию встроено? Хотя бы ключевые слова...
FDS>>Проще говоря, вопрос не в том, надо ли тестировать, а в том, насколько мелкие единицы тестировать. Я предлагаю тестировать относительно крупные единицы, вы — очень мелкие.
IT>Я нигде не предлагал тестировать ни мелкие, ни крупные единицы. Это личное дело каждого. Я тестирую и сценарии и отдельные методы. Чего я не тестирую так это ветки кода. Тут действительно можно застрелиться.
Честно говоря, с моей точки зрения, тестировать все методы — это то же застрелится. По крайней мере у меня методы обычно довольно маленькие. Другой вопрос, если тестировать методы, предназначенные для использования в других приложениях.
В таком случае было бы интересно узнать, сколько строк кода у вас теситрует один автотест (в среднем) [у меня примерно 1000-1500 почти без комментариев ].
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, FDSC, Вы писали:
FDS>>А они точно "юнит", или они всё таки как заглушки на части системы стоят: тогда это уже не совсем ЮТ?
V>А ты точно в состоянии провести границу между ЮТ и не-ЮТ?
Если речь идёт о заглушках-тестах для частей довольно крупной системы, то тут и думать не надо — это не ЮТ. Если конечно, при этом, сами части системы не тестируются ЮТ. Проще говоря, насколько помогают ваши тесты локализовать ошибку, а не просто выявить её?
Здравствуйте, FDSC, Вы писали:
FDS>>>А они точно "юнит", или они всё таки как заглушки на части системы стоят: тогда это уже не совсем ЮТ?
V>>А ты точно в состоянии провести границу между ЮТ и не-ЮТ?
FDS>Если речь идёт о заглушках-тестах для частей довольно крупной системы, то тут и думать не надо — это не ЮТ. Если конечно, при этом, сами части системы не тестируются ЮТ. Проще говоря, насколько помогают ваши тесты локализовать ошибку, а не просто выявить её?
Ты не ответил на вопрос.
Вот у нас есть юнит-тесты для некоторых блоков самого нижнего, потом идут юнит-тесты для более крупных блоков, построенных на основе этих нижних блоков и т.д. по иерархии. Граница где? Когда юнит-тесты прекращают быть юнит-тестами и называются функциональными?
Здравствуйте, FDSC, Вы писали:
FDS>Глупый вопрос: а что в студию встроено? Хотя бы ключевые слова...
В VSTS есть собственный фреймворк для UT, в том числе умеющий автоматически генерить тесты и расцвечивать исходники на предмет code coverage. Для NUnit есть плагин. Кроме того, NUnit-тесты поддерживает и Решарпер, позволяя запускать эти тесты прямо из студии.
Здравствуйте, IT, Вы писали:
IT>Я говорю о ситуации, когда в процессе разработки тесты всё равно надо писать. В случае strlen тест всё равно нужно написать, или ты с этим не согласен?
Видишь ли, предлагаемый тобой сценарий, хоть и существенно менее обременителен, тем не менее сильно расходится с тем, что предлагают идеологи UT. В частности, твой подход приведет к созданию относительно крупных тестов, отражающих некие базовые сценарии применения. А по классике требуется получить как можно больший code coverage с как можно большим диапазоном входных параметров.
Здравствуйте, vdimas, Вы писали:
V>Вот у нас есть юнит-тесты для некоторых блоков самого нижнего, потом идут юнит-тесты для более крупных блоков, построенных на основе этих нижних блоков и т.д. по иерархии. Граница где? Когда юнит-тесты прекращают быть юнит-тестами и называются функциональными?
Unit-тесты, это не столько собственно внешний вид этих тестов, сколько методика тестирования. Т.е. сами юнит тесты могут например быть регрессионными. Одно другого не исключает.
Здравствуйте, AndrewVK, Вы писали:
IT>>Я говорю о ситуации, когда в процессе разработки тесты всё равно надо писать. В случае strlen тест всё равно нужно написать, или ты с этим не согласен?
AVK>Видишь ли, предлагаемый тобой сценарий, хоть и существенно менее обременителен, тем не менее сильно расходится с тем, что предлагают идеологи UT. В частности, твой подход приведет к созданию относительно крупных тестов, отражающих некие базовые сценарии применения.
Ну почему же только сценарии. Отдельные методы и их параметры я тоже тестирую, когда это необходимо. Бывает, что тестируются и ветки кода, но это редко.
AVK>А по классике требуется получить как можно больший code coverage с как можно большим диапазоном входных параметров.
Если в этом есть необходимость, то можно и так. Вопрос лишь в том есть ли такая необходимость на самом деле или это всего лишь дань догме.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, AndrewVK, Вы писали:
V>>Вот у нас есть юнит-тесты для некоторых блоков самого нижнего, потом идут юнит-тесты для более крупных блоков, построенных на основе этих нижних блоков и т.д. по иерархии. Граница где? Когда юнит-тесты прекращают быть юнит-тестами и называются функциональными?
AVK>Unit-тесты, это не столько собственно внешний вид этих тестов, сколько методика тестирования. Т.е. сами юнит тесты могут например быть регрессионными. Одно другого не исключает.
Вот и я про то. Я вот сколько не перечитывал описания методики юнит-тестирования, не смог вывести ее в абсолютно чистом виде.
Один и тот же тест, если он автоматизирован (ключевое слово), может быть:
— юнит тестом
— функциональным тестом
— негативным юнит или негативным функциональным
— включенный в некий тест-сьют — быть частью регрессионной системы
— может быть запущен в десятках-сотнях тредах и быть частью стресс-тестирования (и даже этот сценарий стресс-тестирования может являться, в зависимости от требований, и юнит, и функциональным и быть частью регрессионного)
— ничего не забыл?
А ввиду того, что границы при иерархическом построении автоматизированных тестов нет, то единственным признаком юнит-теста остается выделенное слово.
(это вроде приглашения на медитацию для тех, кто молится именно на юнит-тесты)
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, AndrewVK, Вы писали:
V>>>Вот у нас есть юнит-тесты для некоторых блоков самого нижнего, потом идут юнит-тесты для более крупных блоков, построенных на основе этих нижних блоков и т.д. по иерархии. Граница где? Когда юнит-тесты прекращают быть юнит-тестами и называются функциональными?
Unit. The smallest compilable component. A unit typically is the work of one
programmer (At least in principle). As defined, it does not include any
called sub-components (for procedural languages) or communicating components
in general.
Unit Testing: in unit testing called components (or communicating components)
are replaced with stubs, simulators, or trusted components. Calling
components are replaced with drivers or trusted super-components. The unit is
tested in isolation.
Здравствуйте, mbergal, Вы писали:
V>>>>Вот у нас есть юнит-тесты для некоторых блоков самого нижнего, потом идут юнит-тесты для более крупных блоков, построенных на основе этих нижних блоков и т.д. по иерархии. Граница где? Когда юнит-тесты прекращают быть юнит-тестами и называются функциональными?
M>Может это поможет? Сама ветка здесь.
M>
M>Unit. The smallest compilable component. A unit typically is the work of one
M>programmer (At least in principle). As defined, it does not include any
M>called sub-components (for procedural languages) or communicating components
M>in general.
M>Unit Testing: in unit testing called components (or communicating components)
M>are replaced with stubs, simulators, or trusted components. Calling
M>components are replaced with drivers or trusted super-components. The unit is
M>tested in isolation.
Нет, не помогает. Смотри на выделенное слово. У нас именно так юнит-тесты и организованы, что сначала тестируются компоненты нижнего уровня, получая тем самым статус "trusted", затем, на основе их, прогоняются тесты более сложных компонент. Тест-кейзы при этом изначально расчитаны на то, что компоннеты нижнего уровня заведомо правильно работают, т.е. мы тестируем именно данный высокоуровневый юнит, а не его окружение. И т.д.. В общем, на третьем-четвертом шаге мы уже упираемся в ТЗ и дальше двигаться некуда, ибо полностью выполнен план функциональных тестов.
И граница обнаружена не была.
---------
Дело в том, что иногда заглушки писать принципиально невозможно без усложнения дизайна с целью возможности подменять все заглушками. Первый же пример — это необходимость делать все методы виртуальными, а заглушку реализовать как наследника, переопределяющего ВСЕ методы целевого компоннета/интерфейса, так же надо будет плодить фабрики на ровном месте и т.д. и т.п. Наш подход мне кажется более приближенным к реальности. Тем более, что в условиях дотнета начальный trust-пояс ну о-о-о-очень широк и многофункционален, его с головой хватает на организацию тестирования компонент самого нижнего уровня без написания каких-то стабов и заглушек (чаще всего).
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, mbergal, Вы писали:
V>>>>>Вот у нас есть юнит-тесты для некоторых блоков самого нижнего, потом идут юнит-тесты для более крупных блоков, построенных на основе этих нижних блоков и т.д. по иерархии. Граница где? Когда юнит-тесты прекращают быть юнит-тестами и называются функциональными?
M>>Может это поможет? Сама ветка здесь.
M>>
M>>Unit. The smallest compilable component. A unit typically is the work of one
M>>programmer (At least in principle). As defined, it does not include any
M>>called sub-components (for procedural languages) or communicating components
M>>in general.
M>>Unit Testing: in unit testing called components (or communicating components)
M>>are replaced with stubs, simulators, or trusted components. Calling
M>>components are replaced with drivers or trusted super-components. The unit is
M>>tested in isolation.
V>Нет, не помогает. Смотри на выделенное слово. У нас именно так юнит-тесты и организованы, что сначала тестируются компоненты нижнего уровня, получая тем самым статус "trusted", затем, на основе их, прогоняются тесты более сложных компонент.
Вы им присваиваете статус "trusted" — как я понимаю, проходящие unit tests не дают автоматически компоненту этот статус.
V> Тест-кейзы при этом изначально расчитаны на то, что компоннеты нижнего уровня заведомо правильно работают, т.е. мы тестируем именно данный высокоуровневый юнит, а не его окружение. И т.д.. В общем, на третьем-четвертом шаге мы уже упираемся в ТЗ и дальше двигаться некуда, ибо полностью выполнен план функциональных тестов.
Тогда у вас все компоненты тестируются в изоляции и у вас все тесты component test являются так же и unit-tests.
V>И граница обнаружена не была.
Из-за принятого Вами решения о "trusted components" — но так делают не все, сомневаюсь я что это рекомендуемая практика. (<- Все IMHO).
V>--------- V>Дело в том, что иногда заглушки писать принципиально невозможно без усложнения дизайна с целью возможности подменять все заглушками. Первый же пример — это необходимость делать все методы виртуальными.
Ну или только интерфейсами пользоваться.
V> а заглушку реализовать как наследника, переопределяющего ВСЕ методы целевого компоннета/интерфейса
Угу.
V> так же надо будет плодить фабрики на ровном месте и т.д. и т.п.
OK. Может быть. Мне пока хватало одной — не сильно напрягает. А вставили бы мы IoC с dependency injection было бы еше проще.
Меня пугают другие заморочки с unit test (например chatty mocks) — поэтому у нас большинство тестов — component test.
V> Наш подход мне кажется более приближенным к реальности.
Это самое важное.
V> Тем более, что в условиях дотнета начальный trust-пояс ну о-о-о-очень широк и многофункционален, его с головой хватает на организацию тестирования компонент самого нижнего уровня без написания каких-то стабов и заглушек (чаще всего).
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, GlebZ, Вы писали:
LCR>>>... о срочных проектах. GZ>>Тута есть еще одна штука. Если брать классические процессы, и это не система сделанная на коленке, то обычно действует правило 40-20-40, где 40 процентов времени занимет постановка, 20 программирование, и 40 процентов тестирование и отладка. Юнит-тесты могут сократить последнюю цифру.
V>Если речь идет о типовых проектах, которые делаются пачками, то отношения немного не такие. Субъективно на мой взгляд, примерно 10-80-10. И юнит-тесты есть только для базового функционала наработанного фреймворка.
Вот уж как раз наоборот, для типовых проектов реализация — вообще простая (уже столько раз это сделано и переделано, чего тут думать — бери из прошлых и уточняй по месту). А вот выяснение потребоностей у заказчика и тестирование с отладкой, что все взяли правильно и не перепутали текущие требования с прошлыми — очень даже немалые остаются (хотя и тоже уменьшаются несколько).
Здравствуйте, IT, Вы писали:
AVK>>Видишь ли, предлагаемый тобой сценарий, хоть и существенно менее обременителен, тем не менее сильно расходится с тем, что предлагают идеологи UT. В частности, твой подход приведет к созданию относительно крупных тестов, отражающих некие базовые сценарии применения.
IT>Ну почему же только сценарии. Отдельные методы и их параметры я тоже тестирую, когда это необходимо. Бывает, что тестируются и ветки кода, но это редко.
Ты уж определись — либо ты специально пишешь юнит-тесты, в том числе и в тривиальных местах, либо ты пишешь только те тесты, которые необходимы для отладки написуемого куска.
AVK>>А по классике требуется получить как можно больший code coverage с как можно большим диапазоном входных параметров.
IT>Если в этом есть необходимость, то можно и так.
Так вот в необходимости этогои есть вопрос.
IT> Вопрос лишь в том есть ли такая необходимость на самом деле или это всего лишь дань догме.
Здравствуйте, AndrewVK, Вы писали:
IT>>Ну почему же только сценарии. Отдельные методы и их параметры я тоже тестирую, когда это необходимо. Бывает, что тестируются и ветки кода, но это редко.
AVK>Ты уж определись — либо ты специально пишешь юнит-тесты, в том числе и в тривиальных местах, либо ты пишешь только те тесты, которые необходимы для отладки написуемого куска.
Ты предоставляешь мне какой-то уж слишком ограниченный выбор. Можно я буду использовать юнит тесты там, где мне это нужно для отладки и там, где я сочту это необходимым, чтобы покрыть ими часть функционала во избежании недоразумений в будущем?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, ie, Вы писали:
ie>Неа, она не является ложной, чистая правда. Однако, все многообразие реального мира она действительно не учитывает, надо так: "Если юнит-тестов нет, то программа не работает, а если юнит-тесты есть, то тоже не работает". Вот такие пироги
Эту фразу можно отрефакторить, что бы она стала более читаемой и лаконичной: "Программа не работает!"
Здравствуйте, Mirrorer, Вы писали:
M>Ну что тут можно сказать.. VS2005 рулит Но студия может обеспечить только синтаксическую и семантическую корректность. А когда при рефакторинге ломается логика, то получить максимально быстрый фидбек позволяют именно ЮТ имхо.
Что же это за рефакторинг такой, если при нем ломается логика? Разве что глюк в студии... (насчет VS не знаю, но в IDEA 6.0.2 сталкивался.)
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Что же это за рефакторинг такой, если при нем ломается логика? Разве что глюк в студии... (насчет VS не знаю, но в IDEA 6.0.2 сталкивался.)
Рефакторинг — это не только переименование переменной и выделение метода. Он может быть очень сложным и потому проводимым вручную.
Здравствуйте, prVovik, Вы писали:
ДГ>>Что же это за рефакторинг такой, если при нем ломается логика? Разве что глюк в студии... (насчет VS не знаю, но в IDEA 6.0.2 сталкивался.)
V>Рефакторинг — это не только переименование переменной и выделение метода. Он может быть очень сложным и потому проводимым вручную.
Про ручной рефакторинг — согласен. У самого вертелся в голове пример с переносом логики из java-приложения в хранимые процедуры sql-сервера. Но тут-то речь шла про автоматический рефакторинг.
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Про ручной рефакторинг — согласен. У самого вертелся в голове пример с переносом логики из java-приложения в хранимые процедуры sql-сервера. Но тут-то речь шла про автоматический рефакторинг.
При автоматическом рефакторинге тоже может что-то сломаться. Например, переименовали метод, а его вызов был через reflection.
Здравствуйте, Lloyd, Вы писали:
L>При автоматическом рефакторинге тоже может что-то сломаться. Например, переименовали метод, а его вызов был через reflection.
В IDEA частенько при авто-рефакторинге что-то ломается и без всякой рефлексии. А что делать — мир не идеален.
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Что же это за рефакторинг такой, если при нем ломается логика?
Ну помимо тела программы приходится еще иногда конфиги менять и тому подобное..
И рефлекшен само собой.