Re[10]: Как важно проверять в программах ошибки до конца
От: Erop Россия  
Дата: 22.06.12 08:58
Оценка:
Здравствуйте, landerhigh, Вы писали:

DR>>>Можно конкретный пример, когда правильное поведение системы неизвестно?


E>>Ну торговля на бирже, например, или распознавание речи...


L>О майн готт.

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

Речь тут шла не про юнит-тесты, а про систему, правильное поведение которой не известно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Как важно проверять в программах ошибки до конца
От: Erop Россия  
Дата: 22.06.12 09:00
Оценка:
Здравствуйте, Don Reba, Вы писали:

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


DR>>>Можно конкретный пример, когда правильное поведение системы неизвестно?


E>>Ну торговля на бирже, например, или распознавание речи...


Ты просил пример системы, а не класса.

Если хочешь класс -- то любой классификатор, например нейросеть...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Как важно проверять в программах ошибки до конца
От: AlexGin Беларусь  
Дата: 22.06.12 09:30
Оценка:
Здравствуйте, Michael7, Вы писали:

M>Я иногда кое-что пишу или отлаживаю на Delphi или FreePascal (не только на них и вообще это не так важно). Сегодня отлаживал одну ошибку, программа почему-то падала. Выяснил, что падение возникает из-за ошибок в некоторых данных (это другая история), которые программа забывала проверить на корректность. Добавил проверку. Можно было бы успокоиться, что все заработало, но решил выяснить, из-за чего она все-таки падала при неправильных данных.


M>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию. Ошибался. Теперь удивляюсь, как же я умудрился раньше не нарваться на ошибки в этом месте (дважды вызов Free например из-за этого)


M>Мораль в качестве выводов:


M>1) Если есть ошибка полезно докопаться до ее истоков, а не просто избавиться от нее.

M>2) Можно обнаружить что-то для себя новое в казалось бы давно и хорошо известном.

Когда-то, более 15 лет назад, в книге Тома Свана "Освоение Borland C++ 4.5" я прочитал очень толковую фразу (не дословно, но суть такая):
-Дебаггер — великий учитель!!!

В Delphi отладчик есть?
Думаю что есть (с Delphi не работал, а в C++ Builder отладчик имеется).

Что же мешало Вам, уважаемый Michael7, пройти все это по шагам в отладчике?
Тем более, что exit — это такая штука, которою пользуются — хорошо если один раз в десять лет...
Re[2]: Как важно проверять в программах ошибки до конца
От: Michael7 Россия  
Дата: 22.06.12 10:26
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Когда-то, более 15 лет назад, в книге Тома Свана "Освоение Borland C++ 4.5" я прочитал очень толковую фразу (не дословно, но суть такая):

AG>-Дебаггер — великий учитель!!!

AG>В Delphi отладчик есть?

AG>Думаю что есть (с Delphi не работал, а в C++ Builder отладчик имеется).

Есть конечно отладчик. Причем я пользовался даже не Delphi, а Lazarus, но там тоже есть отладчик, возможно несколько проще, чем в Delphi, но это не важно.

AG>Что же мешало Вам, уважаемый Michael7, пройти все это по шагам в отладчике?

AG>Тем более, что exit — это такая штука, которою пользуются — хорошо если один раз в десять лет...

Обычно в отладчике прохожу, когда что-то не работает и из отладочных сообщений неясно почему же именно. Или если нужно в чужой программе быстро разобраться, тогда тоже, а так вроде и потребности особой не возникало. Тем более, что обычно старался не выходить exit-ом, а так или иначе переходить к блоку finally, к тому же далеко не всегда exit был внутри try, так что повода для ошибки вообще не было. В общем, такой вот парадокс, что можно было очень долго заблуждаться на счет правильной работы exit внутри try.
Re[11]: Как важно проверять в программах ошибки до конца
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 22.06.12 10:47
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ты просил пример системы, а не класса.

E>Если хочешь класс -- то любой классификатор, например нейросеть...

Но и тут поведение известно и прекрасно тестируется. Нейросеть тоже состоит из набора отдельных алгоритмов. Например, для тестирования классификации устанавливаем тестовые веса и проверяем, правильно ли классифицируются тестовые данные. Для тестирования обучения устанавливает тестовые веса и проверяем правильно ли они изменяются для тестового ввода и вывода. Когда всё так обложено тестами, гораздо приятней заниматься оптимизацией.
Ce n'est que pour vous dire ce que je vous dis.
Re[3]: Как важно проверять в программах ошибки до конца
От: AlexGin Беларусь  
Дата: 22.06.12 11:29
Оценка:
Здравствуйте, Michael7, Вы писали:

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


AG>>Когда-то, более 15 лет назад, в книге Тома Свана "Освоение Borland C++ 4.5" я прочитал очень толковую фразу (не дословно, но суть такая):

AG>>-Дебаггер — великий учитель!!!

AG>>В Delphi отладчик есть?

AG>>Думаю что есть (с Delphi не работал, а в C++ Builder отладчик имеется).

M>Есть конечно отладчик. Причем я пользовался даже не Delphi, а Lazarus, но там тоже есть отладчик, возможно несколько проще, чем в Delphi, но это не важно.


AG>>Что же мешало Вам, уважаемый Michael7, пройти все это по шагам в отладчике?

AG>>Тем более, что exit — это такая штука, которою пользуются — хорошо если один раз в десять лет...

M>Обычно в отладчике прохожу, когда что-то не работает и из отладочных сообщений неясно почему же именно. Или если нужно в чужой программе быстро разобраться, тогда тоже, а так вроде и потребности особой не возникало. Тем более, что обычно старался не выходить exit-ом, а так или иначе переходить к блоку finally, к тому же далеко не всегда exit был внутри try, так что повода для ошибки вообще не было. В общем, такой вот парадокс, что можно было очень долго заблуждаться на счет правильной работы exit внутри try.


А почему теперь понадобился этот самый exit?
В моем понимании, для Windows приложений с оконным GUI такой выход — это анахронизм.

ИМХО насколько я понимаю — это выход из приложения командной строки при нештатной ситуации...
Re[4]: Как важно проверять в программах ошибки до конца
От: Michael7 Россия  
Дата: 22.06.12 13:18
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>А почему теперь понадобился этот самый exit?

AG>В моем понимании, для Windows приложений с оконным GUI такой выход — это анахронизм.

Выход из процедуры/функции, а не программы Программы впрочем тоже, но только, если в запускающем файле записано.
Re[10]: Как важно проверять в программах ошибки до конца
От: newCL Россия  
Дата: 23.06.12 03:55
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>2. Ошибки, найденные во время QA на проектах, покрытых юнит-тестами, разительно отличаются от ошибок, найденных на классических проектах. Обычно они лежат в плоскости "а мы считаем, что здесь спеки требуют другого поведения" и "поведение соответствует спекам, но заказчик понял, что ошибся в спеках и поэтому поведение нужно изменить", в то время как багрепорты от QA на классических проектах пестрят "упало", "не работает вообще", "сожрало всю память и опять упало" и прочими WTF.


видел я один такой проект (покрытый тестами).
пришёл ко мне на разработку багрепорт вида:
2012.06.23T7:50Z0001 Упало.... Exception*&^/№*&^
2012.06.23T7:50Z0001 Упало.... Exception*&^/*&^№
2012.06.23T7:50Z9999 Упало.... Exception*&^№"*&^
2012.06.23T7:50Z9999 Упало.... Exception*&^@;*&^
....

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

но "упало" — половина беды, а вот если повисло...
ненавижу все существующие ЯП
Re[10]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 04:37
Оценка:
Здравствуйте, Don Reba, Вы писали:

[...]

DR>Каждый шаг выполняет сторого определённую функцию, для каждого алгоритма известно правильное поведение.


Теоретически всё правильно, но на практике так не получится — это уже доказано опытом. (Даже Гейтс недавно высказывался на эту тему.) Все эти цифро-спектральные методы хороши только для анализа речи того, кто специально говорил для распознавателя и натренирован в таком говорении. В случае же реальной речи огромную долю выполняет контекст и семантический анализ, который ещё не научились формализовывать. Думаю, что коллега Erop имел в виду именно этот аспект.
The God is real, unless declared integer.
Re[11]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 04:50
Оценка:
Здравствуйте, netch80, Вы писали:

DR>>Каждый шаг выполняет сторого определённую функцию, для каждого алгоритма известно правильное поведение.

N>Теоретически всё правильно, но на практике так не получится — это уже доказано опытом.

Впрочем, если речь об *юнит* тестах, то они тут таки возможны, хотя и не на всю логику.
The God is real, unless declared integer.
Re[12]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 05:21
Оценка:
Здравствуйте, landerhigh, Вы писали:

b-3>>давно Present Perfect стало прошедшим? Present как переводится?

L>Рассказать, как переводится Perfect?

L>Это время используется для обозначения действия, завершенного к настоящему моменту без указания конкретного периода в прошлом. То есть "have you done any unit testing at all?" == "писали ли вы тесты когда-либо?". Посыл ложный, о чем я и говорю.


Present Perfect обозначает состояние в настоящем времени, возникшее в результате действий в прошлом и грамматически выраженное через эти самые действия. Например, "я покрасил забор" это Present Perfect. Но "я покрасил забор в равномерный серый цвет, и тут же банда панков его размалевала" — уже не может быть Present Perfect, потому что состояния уже нет, его испортили; это Past Perfect, потому что состояние было в прошлом.

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

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

Возвращаясь к обсуждаемой фразе, да, "Have you done any unit testing at all?" — вполне законный Present Perfect, если подразумевается персональный опыт человека, но вполне может быть недопустимым, если речь о состоянии программы, в которую потом пришла банда быдлокодеров и всё разломала.
The God is real, unless declared integer.
Re[12]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 05:39
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Сравниваешь теплое с мягким. Тесты выполяются автоматически во время каждого билда, и отладочная печать и логи по сравнению с ними находятся в одином ряду с каменным топором по сравнению с современным станком с ЧПУ.


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

L>>> И, пожалуйста, не упоминай конечные автоматы в суе и особенно в разговорах со мной.

L>>> Порву на лоскуты размером в атом, а из того, что осталось, вызову цепную ядерную реакцию.
М>>стадию перехода на личности мы уже миновали и вот уже добрались до прямых угроз. давайте, рвите. мне и правда интересно
L>А вот не надо было соскользывать с темы и приплетать FSM куда не надо.

Всё равно не надо срываться на такое.

L>Цитату можно, где я соглашался?

L>Эти 3000 тестов будут состоять из трех-четырех строчек каждый; трудоемкость их написания на фоне затрат на разработку основного кода незаметна, а объем — вообще странная метрика. Более того, факт написания тестов оказывает положительный эффект на разработку собственно кода, поскольку тестируемый код должен удовлетворять критериям тестируемости, которые магическим образом совпадают с обобщенными критериями "хорошести" и "поддерживаемости" кода. Выполнение этих тестов занимает несколько секунд.
L>Трудоемкость такого подхода совершенно ничтожна по сравнению с затратами, которые потребовались бы на орагнизацию аналогичного по покрытию набора функциональных black-box тестов.

Их сравнивать в принципе нельзя. В реальности нужны и те, и другие.

М>>например, если это пульт управления микроволновой печи -- модель _доказывает_, что нельзя войти в меню из которого потом не выйти. именно, что _доказывает_, причем верификация осуществляется автоматически.

L>А вот тут я, как и обещал, порву тебя на лоскуты. Пульт управления микроволновки — это типичный пример state machine. То, что в ней нет тупиков, доказывается в первую очередь диаграммой состояний вашей машины и таблицей переходов. Верифицируется ручками, глазками, и девайсом /dev/brain. Как и все подобные конечные автоматы.

А у мыщъха оно верифицируется специальной тулзой, которая доказывает наличие пути из любой точки. И эта тулза точно так же может запускаться автоматически и не зависеть от того, что тот, кто в ковырнадцать тысяч ёкарнадцатый раз пролистал FSM на тему "ну чего они тут ещё натворили", случайно нажал PgDn дважды и пропустил какое-то важное изменение.

L> А вот после реализации можно и нужно написать функциональный тест, который в том числе проверит, что из каждого меню можно выйти в $HOME.


И сколько ты будешь писать этот тест?

L>>>Дорогой, ты только что привел примеры двух индустрий,

L>>>где юнит-тестирование проводится практически везде.
М>>и обе индустрии вбухивают в тестирование мегабабло. потому что цена ошибки дороже.
L>Знаем мы, куда они мегабабло вбухивают. На бонусы непричастным и сетрификацию некомпетентными.

Оффтопик и намёк на слив.

L>Нет никаких особых расходов на разработку этих тестов. Вообще, когда спрашивают о расходах на разработку тестов, это является признаком полного непонимания подхода TDD и использования юнит-тестов в разработке. Этот процесс не разделим на составные части.


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

L>Как только разработчик становится адептом церкви TDD на своем опыте узнает преимущество юнит-тестирования, для него юнит-тесты перестают существовать как отдельная сущность.


Я давно знал, что TDD — это не методика, а религия.

L> Для нас процесс разработки есть процесс написания собственно кода и кода, его тестирующего. Они неотделимы друг от друга, как неотделимы и наши собственные оценки затрат и как результат, бюджет. Кроме того, наши оценки временных затрат зачастую являются гораздо более точными, так как, прежде чем приступить к estimations, мы должны не только ответить на вопрос "а что мы будем писать", но и "а как мы это будем автоматически тестировать".


Полностью согласен (только надо учесть ещё и ручное тестирование, хотя бы на верхних уровнях, которое всё равно обязательно).
The God is real, unless declared integer.
Re[10]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 06:17
Оценка:
Здравствуйте, мыщъх, Вы писали:

М>зачем ее собирать, когда она и так есть? http://www.cvedetails.com/ -- пища для размышлений. и ведь во всех этих компаниях есть целые подразделения, занимающиеся исключительно тестированием с нехилым таким бюджетом. а что на выходе? _абсолютно_ _ничего_ работающего хотя бы на 90%. это не значит, что тесты бесполезны. это значит, что на практике ошибки приходится фиксить _после_ релиза на стадии пуско-наладки. причем, эта вполне законная стадия, которой не избежал ни один проект.


Нет. Это всего лишь значит, что разработка строится так, что ТЗ содержит только требования к основному функционалу, но не к защищённости. И точно так же тесты создаются только для основного функционала. Иначе бы на любой потенциальный SQL injection был бы тест, который показывал, что недопустимое не происходит, все входные данные адекватно фильтруются, квотятся и так далее. И так же для других известных проблем.

Посмотри, например, на RFC4475. Тут народ постарался и нарисовал тестовые примеры для парсера. Мы включили требование соответствия этим тестам в ТЗ на свою реализацию (и постепенно движемся к этому — нет принципиальных проблем, но нет времени).

М>при этом далеко не все поддается тестированию. если модуль работает с железом, то все. кранты. даже если железо -- проц. на блоге ms можно найти инфу о том, как проц генерил ошибку доступа к памяти в инструкции типа mov eax, ebx. в ms долго курили очень хорошую траву пока их не торкнуло, что крэш дамп памяти извлекается из памяти. а исключение генерит уже декодированная инструкция глубоко в недрах ЦП, который разогнан сцука и потому там совсем не то, что ожидалось.


Ну так это разогнанный. Естественно, если поставить в такие условия, будет ерунда.
А так — модуль, работающий с железом, можно совмещать с эмуляцией того железа, которая будет проверять хотя бы базовые аспекты.

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


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

М>в том-то и дело, что написать парсер, скажем, XML раз в 100500 раз проще, чем написать тест этого парсера. в обоих случаях требуются глубокие знания XML. если их нет, то парсер написать еще можно и он будет как бы работать, а вот написать для него тест и _доказать_ полноту теста -- это высший пилотаж.


"Полнота теста" в принципе недоказуема, если речь идёт о сколь-нибудь сложных действиях или даже обширных входных данных. Тут вспоминали сортировку — очень показательный пример. Мы в принципе не можем протестировать все варианты, их даже при малом количестве элементов (до сотни) дофига и больше. Но мы можем логически "вычислить" маргинальные случаи, проверить их и предполагать корректность работы на основании такого анализа. Более того, мы можем верифицировать алгоритм математически, для сортировки это достаточно легко; но это не исключает тестирования, потому что наше проецирование реального мира на математическую модель само по себе могло быть проблемным.

И таки да, в случае такой задачи, как парсер XML, надо при его написании думать о том, как тестировать. Как минимум это проверка парсинга элементарных лексем и нарушений структуры.

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


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

М>тесты пишутся тогда и только тогда, когда вероятная цена ошибки превышает затраты на разработку тестов.


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

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


Да нет тут никакой принципиальной границы между требованиями. Есть уровень ответственности, грубо говоря, Microsoft, есть — для ядерных бомбардировщиков, а есть все промежуточные уровни. Ответственность автора программы по управлению рентгеновским аппаратом (помнишь случай, когда тот гнал поток на порядки выше?) — в разы меньше ответственности автора софта для ядерного бомбардировщика, но всё равно цена ей — жизни людей. А есть управление тепловой станцией, когда вроде все будут живы, но в случае проблем — убытки на миллионы. А есть кластер, где случайный останов задачи — десятки килобаксов. Ну и так далее.

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

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


Ты хоть в рассылки им написал?

F>>Это наблюдения из практики как она есть — никаких теорий.

М>в том-то и дело, что тесты -- не панацея. а юнит тесты это как целые числа на фоне всех прочих. и гордится тем, что у нас есть юнит тесты это все равно, что говорить "а я умею считать до ста тысяч миллионов".

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

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


Значит, это другая формальная модель — "понимать то, что называется XML в программе ZMMMLLL".

М>тут кончается теория и начинается реальная жизнь. тест XML парсера, написанный по науке -- бесполезен, ибо парсер падает на "живых" данных, о которых тест и не подозревает. и в чем ценность такого теста? а если взять программу на JavaScript, то как ее тестировать юнит-тестами, если нам нужно, чтобы она нормально работала на всех браузерах? тестировать -- нужно. но не юнит тестами.


И юнит тоже. При достаточно заметном объёме (где-то как jQuery) появляется работа и для них.

М>в реальной жизни основная нагрузка ложится на QA.


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

М> они, в частности, проверяют, что в коде нет ошибок типа SQL-injection и вообще тестируют все, что только можно протестировать. а если у нас есть QA, то зачем вкладываться в юнит-тесты?


Затем, чтобы была ненулевая вероятность успешного прохождения QA.

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


А слишком много и не вкладываем.
The God is real, unless declared integer.
Re[4]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 06:27
Оценка:
Здравствуйте, мыщъх, Вы писали:

М>проблема несколько глубже. результаты уже на лице -- в жабе стало нельзя легально прибивать потоки без участия с их стороны. допустим, мы вызвали скрипт манагер из жабы, который вызывает жаба-скрипт, контролируемый юзером/хакером. допустим, в жаба-скрипте while(1); -- в результате поток висит. легально снять -- нельзя. нелегально можно, но это уже хак.


Вот потому места, где такое требуется, надо писать на Erlang.

М>так же есть расширения для руби и питона, позволяющие вызывать движок google v8. и у большинства нет легальных механизмов отвалиться по тайм-ауту. как ни странно у фокса этот муханизм есть. точнее был. сейчас к нему прикрутили JIT и оно перестало работать (раньше интерпретатор байт-кода тупо считал итерации).


Ну это они зря. Надо внутренний аларм вводить.

а забыть про таймаут — да, элементарно. На днях лечил клиент нашего софта для оракловой базы. Если клиент послал запрос по соединению к базе, но вместо ответа или даже TCP RST с той стороны молчание, то он не в состоянии уйти по таймауту, и эта проблема где-то в недрах OCI libraries. Зато, если соединение было создано не само по себе, а взято из connection pool, можно из другого треда сделать ему drop(), тогда оно сразу выходит из ожидания.

М>если брать обработку исключений в венде, то там можно обнаружить два уровня. первый уровень -- это когда стек уже кончился, но запас по прочности еще есть. в этом момент выбрасывается нормальное исключение о том, что стека нет (на самом деле есть, но мало). фишка в том, что повторно это исключение уже не вызываается и когда стек заканчивается, то он заканчивается, а обработчик исключений требует стека для себя любимого, а стека у нас нет. в XP в этом случае винда вела себя... мягко говоря не совсем так, как описано в документации. процесс умирал в ядре без освобождения ресурсов (точнее, с негарантированным их освобождением). в семерке уже пофиксили это и добавили (грубо говоря) еще один уровень "finally" (в кавычках, потому что finally пришел из плюсов, но его концепция намного шире) и теперь у нас есть (грубо говоря) процедура аварийного завершения процесса (ядерная) и процедура аврального аварийного завершения процесса. разница между ними в том, что одна из них _гарантирует_ выполнение finally, а другая всего лишь намеревается это сделать.


Интересно, но я не понимаю, как тут вообще можно добиться переполнения стека. Имеется в виду стек ядерной фазы?
The God is real, unless declared integer.
Re[9]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 07:10
Оценка:
Здравствуйте, мыщъх, Вы писали:

М>повторяю еще раз -- тест должен _доказать_ полноту и непротиворечивость.


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

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

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

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


Дали бы URL. Это почитать действительно интересно.
А по сути — описанные ошибки это или недогляд людей (как в случае рентгена), или недостаточное покрытие ключевых точек (как во float в первопнях).

М>пытаюсь объяснить еще раз -- сложность _полного_ теста намного превышает сложность того, что мы тестируем.


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

М> откроейте глаза и посмотрите на то, что вас окружает. начиная с программного обеспечения и заканчивая медикаментами. далеко не все это тестируется, а если и тестируется, то неполно и поверхностно.


И именно эти неполные и поверхностные тесты дают то, что она хотя бы в большинстве случаев работает.

М>лопата! вот у вас есть библиотечная гамма-функция. а она у вас есть (если под никсы пишите). и у вас возникает вопрос -- как быстро она работает? насколько сильно ошибается? вы хотите знать подходит ли она вам или нет. у вас есть требования по точности и времени. известны и целевые платформы. дело за малым -- убедиться, что все воркается. и вот тут выясняется, что тестирование функции которая заведово работает выливается в сложную инженерную задачу...


Нет. Оно относительно просто. Потому что надо понимать, что именно и как тестировать.
Надо
1) взять заведомо известные случаи, нарушение которых означает, что что-то совсем принципиально неладно.
Например, lgamma(1.0) и lgamma(2.0) обе должны давать ровно 0.0, а lgamma(0.0) должно возвращать ошибку (NaN и EDOM, если в errno).
2) взять некоторое количество ключевых точек, в которых функция должна вычисляться с адекватной точностью. Например, если мы знаем, что 4! == 24, то lgamma(5.0) должно быть ln(24) == 3.1780538303479458; в зависимости от уровня требования к реализации мы допускаем какую-то погрешность или требуем точного совпадения. Точный набор ключевых точек можно оценить уже изучая реализацию.
3) регулярно проводить вместе с обычными тестами такой, при котором та же функция вычисляется другим, возможно, более тупым и кривым, но заведомо более понятным путём, и сравниваются результаты для нескольких случайно взятых аргументов. Этот тест может сработать далеко не сразу, но если есть проблема, то статистически вероятно он её когда-нибудь покажет, и, вполне возможно, это будет до жалоб юзеров.

М>вот он -- момент просветления. на уровне юнит-теста вы не можете сказать какие у вас требования к данной функции. допустим, время отклика системы должно быть не хуже 15 ms на таком-то железе. это во всей совокупности.


Они могут, если это специфицировано в ТЗ.
The God is real, unless declared integer.
Re[8]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 10:12
Оценка:
Здравствуйте, landerhigh, Вы писали:

L>Списывание отсутствия тестов на недостаточность ресурсов — это безоговорочное признание в собственной некомпетентности и прямая путевка за кассу в Макдональдс. Ситуация, описанная топикстартером, тому доказательство. Написать тест, проверяющий поведение его супер-функции при корректных, некорректных и граничных вхожных данных заняло бы две минуты. Ладно, это у меня. У ТС — ну полчаса максимум. Сколько у него там на отладку ушло времени? Вот то-то и оно.


Ты даже не знаешь, где там "суперфункция", но уже делаешь вывод. А теперь скажи, почему ты предполагал, что результат срабатывания exit() вообще будет проверяться, если ТС предполагал, что exit() завершает всю программу включая код теста?

L>Далее, факториал, точнее, то, что принято называть факториалом, на C++ вычисляется в compile time.


Я хочу посмотреть, как ты напишешь реализацию на C++ факториала в compile time, когда аргумент станет известен только в run time. Код в студию.
The God is real, unless declared integer.
Re[9]: Как важно проверять в программах ошибки до конца
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 23.06.12 10:41
Оценка: 1 (1)
Здравствуйте, netch80, Вы писали:

N>Я хочу посмотреть, как ты напишешь реализацию на C++ факториала в compile time, когда аргумент станет известен только в run time. Код в студию.


Посчитать таблицу всех 12 32-битных или 20 64-битных значений факториала не так сложно.
Ce n'est que pour vous dire ce que je vous dis.
Re[10]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 10:45
Оценка:
Здравствуйте, Don Reba, Вы писали:

N>>Я хочу посмотреть, как ты напишешь реализацию на C++ факториала в compile time, когда аргумент станет известен только в run time. Код в студию.


DR>Посчитать таблицу всех 12 32-битных или 20 64-битных значений факториала не так сложно.


Всё равно лукап в этой таблице должен делаться в run time.
А если скажет, что имел в виду как раз табличный вариант, спросим, 1) при чём тут C++, 2) что делать, если по примеру мыщъха надо будет рассматривать нецелый аргумент
The God is real, unless declared integer.
Re[9]: Как важно проверять в программах ошибки до конца
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 23.06.12 10:51
Оценка: 1 (1)
Здравствуйте, мыщъх, Вы писали:

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


Тест не провалится. Потому что тест рассчитан на функцию, которая считает 1) точно, 2) для натурального аргумента, 3) в пределах стандартного int.
Для другой постановки задачи будет другое ТЗ и под него изменятся как реализация, так и тест.

М>но даже если исходить из допущения, что оптимизация не влечет потерю точности, то у вас таблица все равно не правильная. ну ладно, заполняли от балды. бывает. меня вот что интересует -- с каких это пор размер int'а стал строго определенным? или вы никогда не писали программу под 2+ платформы сразу? если int у нас 64 бита (а такое возможно), то тут нужно сначала посмотреть какой у нас int на данной конкретной платформе, а уже потом выбирать под него таблицу. а если int 16 бит (такое тоже бывает), то ваш тест снова выстрелит мимо.


Под это можно сделать контроль в самом тесте. Если будет в int'е не 32 бита, то на этой платформе тест провалится и будет о чём думать.

М>писать тест, который работает только в паре с определенным компилятором и под определенную платформу с определенными опциями компиляции -- на фига? вот перекомпилировали код и ваш тест показал ошибку. а ошибка не в коде, а в тесте. крысота.


Компилятор и опции тут ни при чём. А затачиваться на 32-битный int сейчас так же нормально, как на реализацию плавучки по IEEE754 или на unix only код.

>> Если понадобится факториал дабла, отрицательных чисел, натуральных дробей, и.т.д,

>> то буду делать по учебнику, применяя подходящие к случаю типы данных.
М>пытаюсь объяснить еще раз. в реальной жизни куча функций типа факториала считается приближенно, ибо точный результат зачастую менее важен, чем скорость вычислений. проблема даже не в том, чтобы вычислить 100000! (можно и по таблице), проблема в том -- как хранить такой большой bignum и что с ним делать.

Надо было взять пример показательнее. Не факториал, а, например, вычисления по RSA.

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


И как это, по-твоему, вычислительная математика ухитряется чего-то достигать, если там всё такое сложное?

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


Само собой, и такое проверяем.

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


С нормальной инфраструктурой подготовки и функционирования тестового окружения — никаких принципиальных проблем. Количество ошибок в самом тесте минимально. Инфраструктура может тестироваться сама по себе, если она превосходит уровень тривиальности. Для проверки корректности также вводятся инверсии.

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


Зачем на понт берёшь, начальник? Нам и так несладко.
The God is real, unless declared integer.
Re[10]: Как важно проверять в программах ошибки до конца
От: Eugeny__ Украина  
Дата: 23.06.12 10:52
Оценка:
Здравствуйте, Don Reba, Вы писали:

N>>Я хочу посмотреть, как ты напишешь реализацию на C++ факториала в compile time, когда аргумент станет известен только в run time. Код в студию.


DR>Посчитать таблицу всех 12 32-битных или 20 64-битных значений факториала не так сложно.


А теперь — для дробных!
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.