Здравствуйте, 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 (!) недели. А написание тестов с нуля? Даже одновременно с кодом? Возможно, что (тесты + отладка < отладки), но определённо не в нашем случае.
Сколько ни пробовал покрыть имеющийся проект юнит-тестами — так пока и не получилось ни разу. Не говоря уже чтобы хорошо было. А вот писать их во время написания кода — как раз гораздо легче и мало отвлекает...