Что не так с юнит-тестами
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 26.07.06 08:21
Оценка: 266 (35) +4 -1 :)))

- Да, да, конечно, — сказал им Роман. — Времени у нас мало.
— Мало? — переспросил я. — Ты ошибаешься. Времени у нас нет вообще!
(с) Стругацкие,


Читая топики имеющих отношения к юнит-тестированию
Unit-тесты vs. контрактно ориентированное программирование
Автор: Lazy Cjow Rhrr
Дата: 12.07.06
,
ООП — перспективы
Автор: NetSlow
Дата: 13.06.06
и конечно
Почему ваш код – отстой
Автор: Владислав Сивяков, Алексей Мудрик (перев
Дата: 20.06.06
у меня возникло стойкое несогласие по некоторым моментам. Но поскольку сообщений было много и мнений было много, то анализ топиков, занял у меня некоторое время. Тем не менее, результат анализа перед вами.

Итак.

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

Реальный мир для нас, небольшой компании, таков.

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

Есть и другие, и о них я буду дальше вести разговор.

Здесь программирование происходит в условиях перманентной нехватки времени. В таких условиях вопрос: "А где юнит-тесты?" звучит как издевательство. Очевидный ответ на этот вопрос: "А может вам ещё танец живота на столе станцевать?".

Другим аспектом является то, что в таких условиях основная часть времени времени выделяется на битву с окружением. Посмотрите в форум по Java. Подавляющее большинство вопросов: "Какого х### Hibernate | Struts | Jboss | AnotherCoolButComplexFramework делает не то, что я от него жду и как его добить". Проектирование сильно кренит в сторону "как сделать так, чтобы оно хорошо клеилось к окружению". Божьей помощью оказывается найти в инете работающий пример и разобраться, почему он-таки работает. Если такого примера нет, то приходится подбирать диаметр бубна, цвет ленточек и звук колокольчиков на нём. Процесс этот, как можно догадаться, недетерминированный. (Я не говорю, что библиотеки суть сплошной глюконат, я о том, что чтобы задействовать тот функционал, который находится в библиотеке, нужно следовать определённым правилам, и если нужных сценариев нет в доке и инете, то их (сценарии) придётся вырабатывать самому).

Создаваемое ПО имеет несколько особенностей: кусок "мясца" средних размеров (почему-то называемого заумным термином "Biznizz Lojig" '), и много кода взаимодействующего с окружением, библиотеками и фреймворками. Соотношение меняется от размера к размеру, но как правило "мясца" заметно меньше.

Худо-бедно победив окружение, делается мрачное внутри, но сносное снаружи ПО, с фичами, которые были жирно начёрканы в виде кривых квадратиков со стрелочками на листе формата A4. Эти фичи прорабатываются руками (такое тестирование обязательно) в виде определённого набора вариантов использования. Эти варианты должны проходить 100% гладко. Однако как только начинаются нестандартные варианты использования, корректная работа увы, не гарантируется. (вероятно только Билли Гейтс может позволить отшутиться на презентации BSoD'а, а для небольших компаний это всё равно что, извините, мордой в дерьмо — неприятно). Вдобавок об отодвигании сроков не может быть и речи.

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

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

1. Писать ЮТ — рутина.
Кто не согласен, может попробовать выработать творческий подход к коду наподобие
assertTrue(collection.size()==0);
collection.add("F*ck");
assertTrue(collection.size()==1);

На мой взгляд единственный элемент творчества здесь — это строковая константа.

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

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

Опять же, по этой же причине (я имею ввиду "ЮТ-рутина") Java вызывает иногда ненависть, поскольку там невозможно достаточно просто написать обобщённый класс ClassX, и протестировать только этот обобщённый класс, а использовать Class1..3.

Написание обобщённого кода вызывает ощутимый оверхед, такой, что проще забить на это дело и не парить моск. Для тех, кто сомневается: представьте например, два больших, почти идентичных класса, причём они:
1. наследуют от одного абстрактного, абстрактный класс менять нельзя;
2. немного различаются статическими полями;
3. немного различаются обычными полями;
4. немного различаются внутренними классами (пусть они даже один интерфейс реализуют);
5. немного различаются набором методов и небольшими кусочками в методах, скажем таким образом
String label = getInSomeComplexWay();
String label = super.getLabel();

Как избавиться от дублирования? (Это очень даже реальный пример, два увесистых классика имели всего 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([R | Free], Allocated, From) ->
    log({'allocate...', [R | Free], Allocated}),
    From ! {resource_alloc, {yes, R}},
        log({Free, [{R, From} | Allocated]}),
        server(Free, [{R, From} | Allocated]);

allocate([], Allocated, From) ->
    From ! {resource_alloc, no},
        server([], Allocated).

Какие типы должны иметь "объекты" для функции allocate? Это очевидно. Например, первый аргумент должен иметь такой тип, чтобы он вёл себя как список, причём если он не пустой, то его можно будет передать в функцию log, затолкать его первый элемент в кортеж вместе с атомом "yes", и послать другому процессу и т.д.

Фактически я только что рассказал, как будет использоваться этот аргумент в функции. И если мне нужно описать этот тип, то это описание будет фактически повторять то, как он (тип) будет использоваться. То есть дублировать уже то, что написано в самой функции.

Может этот тип ещё где понадобится? Для Эрланга это нехарактерно — каждая функция уникальна, и следовательно аргументы используются уникальным образом. Тип как будто вспыхивает на мгновение при входе в функцию и исчезает после выхода из функции.

Для Явы однако всё по-другому. Какой-нибудь InputStream может быть воткнут повсюду в программе и в каждой точке маскировать разные объекты. Вот теперь я попытаюсь ответить на вопрос, почему статическая типизация работает (хоть и не даёт фантастических результатов).

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

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




Подвожу итог.

В одном предложении: вопрос написания ЮТ — это вопрос расстановки приоритетов.

В условиях ограниченного времени приходится выбирать наиболее приоритетные задачи. Поскольку работоспособность кода напрямую зависит от архитектуры, понимания проблемы и эффективного использования окружения, то время выделяется прежде всего на эти задачи. И так как итоговый результат получается удовлетворительный, то юнит-тесты выпадают из рассмотрения. Возможно такие быстрые проекты нужно писать на других языках (ФЯ или тех же динамических) или другим способом (XP, TDD), но без обкатки это большой риск.

Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет, то программа не работает", то у меня закрадывается сомнение — может мы действительно делаем вещи неправильно?

PS: Текст получился великоват, поэтому спасибо за уделённое внимание.
Минусы? Тож спасибо, только маленькая просьба: укажите место с чем именно не согласны.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re: Что не так с юнит-тестами
От: Cyberax Марс  
Дата: 26.07.06 09:06
Оценка: 10 (2) +2
Lazy Cjow Rhrr wrote:
> Здесь программирование происходит в условиях /перманентной/ нехватки
> времени. В таких условиях вопрос: "А где юнит-тесты?" звучит как
> издевательство. Очевидный ответ на этот вопрос: "А может вам ещё танец
> живота на столе станцевать?".
Не знаю, по моему опыту юниттестирования — они как раз помогают писать
быстрее.

> Если такого примера нет, то приходится подбирать

> диаметр бубна, цвет ленточек и звук колокольчиков на нём. Процесс этот,
> как можно догадаться, недетерминированный.
Не знаю, у меня после многих лет работы выработался рефлекс: "Эта $$%*#$
не работает??? Да я щас возьму дебаггер и отлажу ее нафиг!" (поэтому я
стараюсь использовть только продукты с исходниками).

Ну а то что на настройку и подгонку надо выделять дополнительное время в
проекте — это само собой разумеешеся.

> *1. Писать ЮТ — рутина.*

> Кто не согласен, может попробовать выработать творческий подход к коду
> наподобие
> На мой взгляд единственный элемент творчества здесь — это строковая
> константа.
Ага, но такой код пишется на автомате.

> *2. Написание ЮТ отнимает значительное время и требует внимания.*

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

> *3. Проверять код взаимодействующий с окружением скорее всего не имеет

> смысла.*
> (Такая нестрогая формулировка потому, что созданные примеры,
> показывающие /как/ надо готовить библиотеки можно назвать
> интеграционными тестами, они выполняют роль поэтапных проверок при
> разрешении сложных ситуаций).
Угу, поэтому TDD часто неприменим. Тестировать GUI-код с помощью тестов
почти невозможно, а когда возможно — то часто бессмысленно.

> Так вот, чтобы протестировать код, нужно написать правильный конфиг, ну

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

Если код зависит от фреймворка — то либо использовать эмуляцию
интерфейсов фреймворка (google: mock objects), либо курить бамбук.

> Чем в данных условиях могут помочь юнит-тесты? А ничем. Но так как умные

> сволочи вроде Эккеля, Фаулера и Бека говорят, что "если юнит-тестов нет,
> то программа не работает", то у меня закрадывается сомнение — может мы
> действительно делаем вещи неправильно?
Просто надо помнить: "всякое общее выражение — неверно".

По-моему, использование тестов во многих случаях ничем не вредит
разработке. Например, я пишу интерпретатор и добавляю обработку
инструкции IMPORT_MODULE. Логично, что мне ее надо как-то отладить — а
для этого надо написать тестовую программу. После того, как новая
инструкция интерпретатора работает — нужно просто добавить в тестовую
программу заголовок с эталонным выводом, и тест готов.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: Что не так с юнит-тестами
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 26.07.06 09:33
Оценка: 8 (1) +1
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Итак.


LCR>Высказывание "Если юнит-тестов нет, то программа не работает" — это догма. И как любая другая догма она является ложной, поскольку не учитывает многообразие реального мира.


Вот с этим я не согласен , поскольку не видел подобного утверждения в перечисленных форумах (вероятно просмотрел?).

Может тебе будет интересно, что я год назад высказал по поводу unit-тестов (в основном для C++): Re[7]: Зачем нужен cppunit?
Автор: eao197
Дата: 21.09.05
. Мне кажется, что в основных идеях мы с тобой довольно сильно пересеклись, хотя твое описание проблемы гораздо серьезнее.

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++.
Re[2]: Что не так с юнит-тестами
От: GlebZ Россия  
Дата: 26.07.06 09:49
Оценка:
Здравствуйте, eao197, Вы писали:

E>Вот с этим я не согласен , поскольку не видел подобного утверждения в перечисленных форумах (вероятно просмотрел?).

Почему ваш код – отстой
Автор: Владислав Сивяков, Алексей Мудрик (перев
Дата: 20.06.06
см. Первую главу. Не очень адекватная статья.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Что не так с юнит-тестами
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 26.07.06 09:58
Оценка:
Здравствуйте, GlebZ, Вы писали:

E>>Вот с этим я не согласен , поскольку не видел подобного утверждения в перечисленных форумах (вероятно просмотрел?).

GZ>Почему ваш код – отстой
Автор: Владислав Сивяков, Алексей Мудрик (перев
Дата: 20.06.06
см. Первую главу.


Нет, там по другому, там отстоем обзывают. А работающий и приносящий деньги код вполне можно обозвать отстоем, фигней, гадостью, ламерством, признаками ошибок в ДНК и пр. -- работающий код все это спокойно перенесет

Речь шла о фразе:

"Если юнит-тестов нет, то программа не работает"

Программа вполне может работать без unit-тестов, проверено на практике.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Что не так с юнит-тестами
От: minorlogic Украина  
Дата: 26.07.06 10:01
Оценка:
Читал ветку по контрактному программированию и юнит тесты , читаю эту .

Мне кажется забыт очень важный момент. Почему так преданы забвению старые добрые методы отладки применяемые нашими дедушками ?


SomeObj::do()
{
ASSERT( this->check_obj_invariants());
......
ASSERT( this->check_obj_invariants());
}

Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы.
Хотите рассмотреть на примерах ? С удовольствием.
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: Что не так с юнит-тестами
От: Lloyd Россия  
Дата: 26.07.06 10:04
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы.

Это не является юнит-тестом, т.к. требует участия человека, поторый перевел бы приложение в такое состояние чтобы ассерт сработал.
Re[4]: Что не так с юнит-тестами
От: GlebZ Россия  
Дата: 26.07.06 10:07
Оценка: -1 :)
Здравствуйте, eao197, Вы писали:

E>Речь шла о фразе:

"Если юнит-тестов нет, то программа не работает"

Утверждение 1:

Ваш код – отстой, если он не работает

Утверждение 2:

Если ваш код не имеет тестов, он – отстой.

Сокращаем данные утверждения найденные в главе, получаем исходное сообщение.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Что не так с юнит-тестами
От: GlebZ Россия  
Дата: 26.07.06 10:07
Оценка: 1 (1)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>1. Писать ЮТ — рутина.

По разному. Если у тебя на выходе xml полученный с эталонной базы данных, и ты его должен проверить по нескольким параметрам, то тут уже меньше рутины и больше творчества. По таким тестам и рефакторинг проводится. К тому же у тестов есть дополнительный бонус: он показывает/уточняет разработчику — что же должна делать его функциональность в данном конкретном месте.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Что не так с юнит-тестами
От: vvaizh http://izh-test.sourceforge.net/
Дата: 26.07.06 10:15
Оценка: 8 (1)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

На самом деле проблема самих unit-тестов в том, что они тестируют совсем не то что тестирует заказчик..
заказчик тестирует полное приложение, а unit тесты тут как раз лажают..
нужны именно функциональные тесты.. минимум..

и только если всё приложение вдруг перестаёт работать нужно прописывать тесты для его частей

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

что касается рутины описания

assertTrue(collection.size()==0);
collection.add("F*ck");
assertTrue(collection.size()==1);


то как я уже писал тут http://www.rsdn.ru/Forum/Message.aspx?mid=1996866
Автор: vvaizh
Дата: 12.07.06


проще сваливать аггрегатные структуры в текстовый файл и сравнивать его
рутины будет гораздо меньше
http://izh-test.sourceforge.net/russian/introduction.html
Re[2]: Что не так с юнит-тестами
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 26.07.06 10:26
Оценка:
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>программу заголовок с эталонным выводом, и тест готов.
Да, в твоём случае ЮТ очень уместно. Однако основной тезис моего высказывания: зачем делать юнит-тесты если можно их не делать?
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: Что не так с юнит-тестами
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 26.07.06 10:26
Оценка:
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>Как видишь, есть только один положительный момент

Спасибо за развёрнутый ответ-дополнение.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[3]: Что не так с юнит-тестами
От: minorlogic Украина  
Дата: 26.07.06 10:30
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, minorlogic, Вы писали:


M>>Что является и контрактным програмированием в рамках языка и юнит тестом не требующим окружения , а запускаемом во время штатной работы.

L>Это не является юнит-тестом, т.к. требует участия человека, поторый перевел бы приложение в такое состояние чтобы ассерт сработал.

Наверное я скажу глупость , а ваши юнит тесты сами себя запускают ?
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[3]: Что не так с юнит-тестами
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 26.07.06 10:30
Оценка: 1 (1)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Да, я понимаю, что в долгосрочной перспективе ЮТ нужны, и чем дальше от начала, тем нужнее. Я просто описал ситуацию, где они приносят в основном вред (тратят время и действуют на нервы), а польза не так чтобы заметна.


Ща провокационную вещь скажу, но все таки: если в условиях цейтнота не хватает времени на тестирование приложения (в том числе и на написание unit-тестов), то это является признаком того, что используется не самый подходящий инструмент (не только и не столько язык программирования, сколько набор библиотек/фреймворков).


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Что не так с юнит-тестами
От: Lloyd Россия  
Дата: 26.07.06 10:31
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Наверное я скажу глупость , а ваши юнит тесты сами себя запускают ?


Нет, их сапускает студия.
Re[4]: Что не так с юнит-тестами
От: ekamaloff Великобритания  
Дата: 26.07.06 10:35
Оценка: +1
Здравствуйте, 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
Re[5]: Что не так с юнит-тестами
От: raskin Россия  
Дата: 26.07.06 10:40
Оценка:
GlebZ wrote:
> E>Речь шла о фразе:
>
> "Если юнит-тестов нет, то программа не работает"
>
> Утверждение 1:
>
> Ваш код – отстой, если он не работает
>
> Утверждение 2:
>
> Если ваш код не имеет тестов, он – отстой.
>
> Сокращаем данные утверждения найденные в главе, получаем исходное
> сообщение.

А, если Б.
Если В, то А.
Связь между В и Б?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Что не так с юнит-тестами
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 26.07.06 10:40
Оценка:
vvaizh,

V>На самом деле проблема самих unit-тестов в том, что они тестируют совсем не то что тестирует заказчик..

V>заказчик тестирует полное приложение, а unit тесты тут как раз лажают..
V>нужны именно функциональные тесты.. минимум..
V>и только если всё приложение вдруг перестаёт работать нужно прописывать тесты для его частей
V>т.е. не снизу вверх по дереву компонентов, а сверху вниз..

Воот. Функциональные тесты — товарищ копирует себе новоиспечённый дистрибутив, задаёт вопрос "а что эта прога должна делать?" и потом потирая ручки "ща, посмотрим...".

V>что касается рутины описания

V>
V>assertTrue(collection.size()==0);
V>collection.add("F*ck");
V>assertTrue(collection.size()==1);
V>


V>то как я уже писал тут http://www.rsdn.ru/Forum/Message.aspx?mid=1996866
Автор: vvaizh
Дата: 12.07.06

V>проще сваливать аггрегатные структуры в текстовый файл и сравнивать его рутины будет гораздо меньше
БТВ, мне тоже приходила мысль про сравнение с эталонным выводом, но во-первых, его же тоже нужно формировать руками; во-вторых такая конструкция очень неустойчива по отношению к рефакторингу. Но всё-равно спасибо.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[5]: Что не так с юнит-тестами
От: Centaur Россия  
Дата: 26.07.06 10:42
Оценка:
Здравствуйте, GlebZ, Вы писали:

E>>Речь шла о фразе:

"Если юнит-тестов нет, то программа не работает"

GZ>Утверждение 1:

Ваш код – отстой, если он не работает

GZ>Утверждение 2:

Если ваш код не имеет тестов, он – отстой.

GZ>Сокращаем данные утверждения найденные в главе, получаем исходное сообщение.

Так нельзя сокращать, ибо из (S <= !W) && (!T => S) не следует (!T => !W). 1 утверждает не «тогда и только тогда», а «в частности».
Re[6]: Что не так с юнит-тестами
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 26.07.06 10:46
Оценка:
raskin,

R>А, если Б.

R>Если В, то А.
R>Связь между В и Б?

Да ладно, там рядом есть вполне характерная фраза

Без адекватных тестов (подразумевая – как по количеству, так и по качеству), вы просто не можете иметь уверенность в том, что ваш код работает как нужно.

quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.