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>>