Я иногда кое-что пишу или отлаживаю на Delphi или FreePascal (не только на них и вообще это не так важно). Сегодня отлаживал одну ошибку, программа почему-то падала. Выяснил, что падение возникает из-за ошибок в некоторых данных (это другая история), которые программа забывала проверить на корректность. Добавил проверку. Можно было бы успокоиться, что все заработало, но решил выяснить, из-за чего она все-таки падала при неправильных данных.
Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию. Ошибался. Теперь удивляюсь, как же я умудрился раньше не нарваться на ошибки в этом месте (дважды вызов Free например из-за этого)
Мораль в качестве выводов:
1) Если есть ошибка полезно докопаться до ее истоков, а не просто избавиться от нее.
2) Можно обнаружить что-то для себя новое в казалось бы давно и хорошо известном.
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию.
Не в качестве сарказма, а действительно любопытно — 2ALL: а где нибудь есть иное поведение?
И можно как нибудь вывернуться и это переопределить, скажем, на Java?
--
Спасибо
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Delphi еще с 90-х годов ... exit внутри try...finally
объясните идиоту, пожалуйста,
как можно использовать try...finally и не знать как оно работает?
Вы ведь где-то прочитали об исключениях, примеры учебные писали наверняка..
как так?
книжек под делфе не читали, в справку не заглядывали, а писали так же как на Turbo Pascal 7.0?
обработку исключений подсмотрели у соседа?
я не понимаю, правда....
это вне моего мировоззрения.
ненавижу все существующие ЯП
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally.
программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С
сорри, ниче личного, но это реально факт.
In P=NP we trust.
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, newCL, Вы писали:
CL>Здравствуйте, Michael7, Вы писали:
M>>Delphi еще с 90-х годов ... exit внутри try...finally
CL>объясните идиоту, пожалуйста, CL>как можно использовать try...finally и не знать как оно работает?
Можно, как выяснил на своем опыте. В том и мораль, что можно оказывается чего-то не знать там, где давным давно, казалось бы все знал.
CL>Вы ведь где-то прочитали об исключениях, примеры учебные писали наверняка.. CL>как так?
Конечно. И это даже работает успешно, в конце-концов, не так часто exit использовал, кроме того, дублирование блока перед exit-ом далеко не всегда приводило к ошибкам. Анекдот, но так и есть.
CL>книжек под делфе не читали, в справку не заглядывали, а писали так же как на Turbo Pascal 7.0? CL>обработку исключений подсмотрели у соседа?
В книжке подробно описывалось как работают исключения, а вот о таком нюансе работы exit в старой еще 90-х годов книжке не было. Просто пропущен этот момент, а exit я знал еще действительно со времен турбо-паскаля. Затем казалось естественным, что он вызывает мгновенный выход.
Если бы я изучал Delphi с нуля и в 2000-х, возможно, что не оказался в заблуждении.
CL>я не понимаю, правда.... CL>это вне моего мировоззрения.
Я тоже не понимаю, теперь надо свой код везде пересмотреть
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, carpenter, Вы писали:
C>я както во фрискейле работал — так у них там с одной игрушкой типа волка ловящего яйца, C>гдето на 14 часу игры проскакивал глюк .
И?
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, carpenter, Вы писали:
C>я както во фрискейле работал — так у них там с одной игрушкой типа волка ловящего яйца, C>гдето на 14 часу игры проскакивал глюк .
вы все наверняка знаете что в микроокнтроллерных приложениях это рядовое явление, и отфиксить железку стоит серьезных трудозатрат
Мы не отступили, а изменили направление атаки!
Re[2]: Как важно проверять в программах ошибки до конца
D>программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С
хотел поправить, но потом посмотрел сообщения — и не стал. не хочется бороться с такой страстью к обобщениям.
D>сорри, ниче личного, но это реально факт.
продолжайте плиз. человечество замерло в ожидании новых откровений.
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, djs_, Вы писали:
_>Здравствуйте, Michael7, Вы писали:
M>>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию.
_>Не в качестве сарказма, а действительно любопытно — 2ALL: а где нибудь есть иное поведение? _>И можно как нибудь вывернуться и это переопределить, скажем, на Java?
Да, можно. Написать System.exit(...);
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Я иногда кое-что пишу или отлаживаю на Delphi или FreePascal (не только на них и вообще это не так важно). Сегодня отлаживал одну ошибку, программа почему-то падала. Выяснил, что падение возникает из-за ошибок в некоторых данных (это другая история), которые программа забывала проверить на корректность.
Вот чтобы подобной ерундой не заниматься, и были придуманы юнит-тесты.
Здравствуйте, Deprivator, Вы писали:
D>Здравствуйте, Michael7, Вы писали:
M>>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally.
D>программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С D>сорри, ниче личного, но это реально факт.
Знаете, ничего личного, но, например, я, с высоты 11+-летнего опыта промышленной разработки на целой куче императивных языков, не вижу принципиальной разницы между дельфи, крестиками, джавой, шарпом, и чем-бы то ни было ещё императивным. В разных языках есть разные плюшки и фичи, иногда кажущиеся ненужными, но при этом, на самом деле, являющиеся весьма важными. Суть и стиль разработки всё равно не меняется. Не хочу начинать холивар, но дельфи — вполне нормальный императивный объектно-ориентированный язык. И довольно эффективный, учитывая мощь VCL, лёгкость клепания формочек, и офигенский RTTI. Другим компилируемым языкам до этого RTTI -- пахать и сеять. Другой вопрос, что сам факт использования exit() не говорит в пользу автора. Это, имхо, примерно как goto.
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию. Ошибался. Теперь удивляюсь, как же я умудрился раньше не нарваться на ошибки в этом месте (дважды вызов Free например из-за этого)
после второго курса любая прога на делфи начиналась у меня с {$O-}. Раз потратил вечер на понимание как в коде
for i:=0 to 7 do
...
i принимает значение 8, 9 и только потом выходит. А ответ прост как сало без хлеба: баг оптимизации.
If the message above is in English — means I'm wasting my work time and work computer to post here. No hard feelings
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, newCL, Вы писали:
L>>Вот чтобы подобной ерундой не заниматься, и были придуманы юнит-тесты.
CL>правильно, они придуманы чтоб другой ерундой заниматься.
Тем, для кого юнит-тесты эквивалентны занятию ерундой, срочно рекомендуется сменить профессию. На сантехника или там развозчика пиццы.
Других мнений по этому поводу быть не может.
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, newCL, Вы писали:
L> для кого юнит-тесты эквивалентны занятию ерундой, срочно сменить профессию. L> Других мнений по этому поводу быть не может.
а вы тесты писали? насколько серьезно подходили к процессу их разработки? у вас была формальная модель, доказывающая корректность, непротиворечивость и полноту теста? сомнительно. и какая польза от теста, который что-то тестирует? конечно, польза есть, но если вы углубитесь в теорию и практику тестирования, то очень быстро убедитесь, что существуют и другие пути.
например, построив блок-схему можно визуализировать косяки и баги, которые хрен какой тест отловит. а что касается юнит-тестов, то у них столько ограничений, что лучше даже не начинать. и в условиях ограниченных ресурсов тесты не пишутся. представьте, что вы на экзамене. у вас пять задач и вы прикидываете, что времени хватает только на решение, но на проверку уже не остается. что вы будете делать? согласитесь, тут все зависит от сложности задач и вашей аккуратности. если вы не раздолбай и статистически вы ошибаетесь в одной задаче из десяти, то у вас хорошие шансы сдать по крайней мере четыре задачи, а то и все пять. а если проверка занимает больше времени, чем решение (а, обычно, это так и есть), то вы решите одну или две задачи и все скажут, что вы дурак. чистая математика, ничего личного.
в чем принципиальная разница:
а) программу запустили и она вроде как работает;
б) программа прошла все тесты, которые вы написали.
а принципиальной разницы и нет. программа прошла все тесты, вы ее запустили, а она взяла и упала. потому что если вы не можете написать программу без ошибок, то почему вы думаете, что ошибок не будет в тесте? они там будут. пример из жизни. знакомый писал тест для факториала. есть проверка на ноль, но нет проверки на отрицательные числа. нет проверки нецелых чисел (а для них тоже можно вычислить факториал). мой тест показал, что функция выдает некорректный результат как для отрицательных чисел так и для дробных. то есть юнит-тест ни хвоста не доказывал. потому что программист, который писал функцию факториала был не в курсе что такое факториал вообще и очень сильно удивился, когда _все_ калькуляторы считали факториалы дробных чисел. программист сказал, что они все идиоты и едут по встречной, а он находится в своем ряду.
вот и скажите мне какая польза от таких тестов? ведь если функция факториала написана с ошибкой потому что программист считает факториал только для целых чисел, то и тест функции факториала, написанный тем же программистом, тестирует факториалы только целых чисел. а если программист знает как считать факториалы для дробных чисел, то тут возникает другой вопрос -- с чем сверять результат? нужна эталонная функция факториала, а у нас ее нет (ну будем считать, что нет), а если обратиться к реальной жизни, где факториалы считаются приближенно, то даже при наличии эталонной функции очень сложно написать функцию для сравнения результатов -- это баг или мы все еще в рамках допустимой точности вычислений. допустим, эталонная функция ушла по максимуму вниз, а наша функция ушла по максимуму вверх. оба результата верны, но попытка их сравнения уже выходит за рамки приличия.
если вы не согласны и уверены в себе и своих знаниях -- плз, напишите функцию факториала вместе с тестом.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[5]: Как важно проверять в программах ошибки до конца
Если никто не знает как это должно работать, ничего не поможет. Юниттесты скорее для другого: ловить случаи когда все работало и вдруг бац — сломалось.
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, linuz, Вы писали:
L>Если никто не знает как это должно работать, ничего не поможет. Юниттесты скорее для другого: ловить случаи когда все работало и вдруг бац — сломалось.
ок. factorial = gamma(n) + 1. если гамма считается приближенно, то factorial = gamma(n), но при этом 0! выдаст очень странный результат. допустим, в оригинале было factorial = gamma(n) + 1, кто-то убрал '+1'. юнит тест не проверял факторил нуля. и все типа работает. а потом -- бац! и кто-то передал в функцию ноль. чем поможет юнит-тест? а ничем.
или вот классический случай вычисления факториала через рекрусию:
int factorial(int n) {
return n == 0 ? 1 : n * factorial(n — 1);
}
передайте функции -1 и посмотрите, что произойдет.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
l> Тем, для кого юнит-тесты эквивалентны занятию ерундой, срочно рекомендуется сменить профессию. На сантехника или там развозчика пиццы. l> Других мнений по этому поводу быть не может.
Интересно за что сантехников обидели ) Думаете так просто сантехником работать или там думать не надо? )
Здравствуйте, мыщъх, Вы писали:
L>> для кого юнит-тесты эквивалентны занятию ерундой, срочно сменить профессию. L>> Других мнений по этому поводу быть не может. М>а вы тесты писали? насколько серьезно подходили к процессу их разработки?
Почему в прошедшем времени?
Остальное поскипано как очередная история очередного ниасилинга с кучей оправданий одно другого убедительнее. Обсуждения не заслуживает.
Здравствуйте, wander, Вы писали:
W>Интересно за что сантехников обидели ) Думаете так просто сантехником работать или там думать не надо? )
Почему же обидел? Просто за пропущенное юнит-тестирование (убедиться в отсутствии протечек) сантехник, в отличие от криворучки-программиста, может вполне получить неиллюзорных люлей непосредственно от заказчика и порой прямо не доходя до кассы. Отделаться сдавленными матами от коллег, которые потом придут это поддерживать, не выйдет.
N>после второго курса любая прога на делфи начиналась у меня с {$O-}. Раз потратил вечер на понимание как в коде
N>
N>for i:=0 to 7 do
N> ...
N>
N>i принимает значение 8, 9 и только потом выходит. А ответ прост как сало без хлеба: баг оптимизации.
Не нарывался на именно такой баг. Это в какой версии он был?
В любом случае, в моей ситуации оптимизация не причем и бага не было, было очень неприятно меня удивившее не точное знание как работают исключения или вернее, как работает exit.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, HelgSpb, Вы писали:
> Другой вопрос, что сам факт использования exit() не говорит в пользу автора. Это, имхо, примерно как goto.
И exit и goto в определенных обстоятельствах очень удобны. Например, чтобы быстро выйти из вложенного цикла. Как раз потому что я редко пользовался exit-ом, такое непонимание его работы долго оставалось незамеченным. Ну и плюс, оказывается, в реальных программах функции работы с памятью могут чаще, чем кажется, прощать ошибки.
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Не нарывался на именно такой баг. Это в какой версии он был?
7я кажется, может 6я. Думаю воспроизвести будет непросто, надо какое-то стечение случайных факторов
M>В любом случае, в моей ситуации оптимизация не причем и бага не было, было очень неприятно меня удивившее не точное знание как работают исключения или вернее, как работает exit.
дык на то он и finally
If the message above is in English — means I'm wasting my work time and work computer to post here. No hard feelings
Re[5]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали: М> программист, который писал функцию факториала был не в курсе что такое факториал вообще и очень сильно удивился, когда _все_ калькуляторы считали факториалы дробных чисел. программист сказал, что они все идиоты и едут по встречной, а он находится в своем ряду.
А можно для тупых поподробней. Я всегда считал, что факториал определён только для целых неотрицательных чисел. Гамма функция это какбы не совсем факториал.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, HelgSpb, Вы писали:
D>>программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С D>>сорри, ниче личного, но это реально факт.
HS>Знаете, ничего личного, но, например, я, с высоты 11+-летнего опыта промышленной разработки на целой куче императивных языков, не вижу принципиальной разницы между дельфи, крестиками, джавой, шарпом, и чем-бы то ни было ещё императивным.
между тем она есть. и даже не в самом языке дело.
дельфи создает иллюзию простоты, там низкий порог вхождения, типичный дельфист — это формошлеп, слабо представляющий внутреннее устройство системы со всеми отсюда вытекающими последствиями.
разумеется, про всех не говорю, говорю про тенденцию.
лет 10 назад мне довелось отсмотреть кучу (больше сотни) мелких проектов, сделанных разными людьми; больше половины из них на дельфи.
статистика однозначная — сделанное на дельфи очень сильно проигрывает тому же С++.
In P=NP we trust.
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, djs_, Вы писали:
M>>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию.
_>Не в качестве сарказма, а действительно любопытно — 2ALL: а где нибудь есть иное поведение?
В Java также (exit — читай return). И это, кстати, это довольно стандартный вопрос на собеседованиях и во всяких тестах.
_>И можно как нибудь вывернуться и это переопределить, скажем, на Java?
System.exit()
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, Dolios, Вы писали:
D>Здравствуйте, мыщъх, Вы писали: М>> программист, который писал функцию факториала был не в курсе что такое факториал вообще и очень сильно удивился, когда _все_ калькуляторы считали факториалы дробных чисел. программист сказал, что они все идиоты и едут по встречной, а он находится в своем ряду. D>А можно для тупых поподробней. Я всегда считал, что факториал определён только для целых неотрицательных чисел. Гамма функция это какбы не совсем факториал.
У Кнута, буквально чютьли не на первых страницах есть непрерывный график факториала.
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию. Ошибался. Теперь удивляюсь, как же я умудрился раньше не нарваться на ошибки в этом месте (дважды вызов Free например из-за этого)
Всегда вспоминай этот случай, прежде чем создавать темы, подобные этой
Здравствуйте, мыщъх, Вы писали:
М>Здравствуйте, linuz, Вы писали:
L>>Если никто не знает как это должно работать, ничего не поможет. Юниттесты скорее для другого: ловить случаи когда все работало и вдруг бац — сломалось. М>ок. factorial = gamma(n) + 1. если гамма считается приближенно, то factorial = gamma(n), но при этом 0! выдаст очень странный результат. допустим, в оригинале было factorial = gamma(n) + 1, кто-то убрал '+1'. юнит тест не проверял факторил нуля. и все типа работает. а потом -- бац! и кто-то передал в функцию ноль. чем поможет юнит-тест? а ничем.
Я вам про фому, а вы мне про ерему. Вы как раз про тот случай когда автор кода толком не понимает чего он от своего кода хочет. А я про то, что юниттесты нужны чтобы не отвалилось что-то что раньше точно работало.
М>или вот классический случай вычисления факториала через рекрусию:
М>int factorial(int n) { М> return n == 0 ? 1 : n * factorial(n — 1); М>}
Вариант безглючный и самотестирующийся. Если понадобится факториал дабла, отрицательных чисел, натуральных дробей, и.т.д, то буду делать по учебнику, применяя подходящие к случаю типы данных.
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>И exit и goto в определенных обстоятельствах очень удобны. Например, чтобы быстро выйти из вложенного цикла. Как раз потому что я редко пользовался exit-ом, такое непонимание его работы долго оставалось незамеченным. Ну и плюс, оказывается, в реальных программах функции работы с памятью могут чаще, чем кажется, прощать ошибки.
Это знаешь, как на красный иногда можно проехать. Можно, конечно. И временами действительно удобно. Но именно из-за таких решений в свою пользу и появляются ошибки. Решил ты, что здесь goto удобен, Вася Пупкин тоже решил в свою очередь, а потом и Баба Марья написала такую фигню в другом месте. И оба-на! Теперь у вас куча goto в проекте, написанные разными людьми. Потому и говорят: не пиши goto. Вот просто не пиши и всё.
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, LLIMblrA, Вы писали: LLI>У Кнута, буквально чютьли не на первых страницах есть непрерывный график факториала.
Факториала? Я не спорю, что есть функции, которые проходят через все точки, в которых определен факториал (гамма-функция). Но сам факториал определен только для целых неотрицательных чисел. Педивикия со мной согласна.
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, MxMsk, Вы писали:
MM>Здравствуйте, Michael7, Вы писали:
M>>И exit и goto в определенных обстоятельствах очень удобны. Например, чтобы быстро выйти из вложенного цикла. Как раз потому что я редко пользовался exit-ом, такое непонимание его работы долго оставалось незамеченным. Ну и плюс, оказывается, в реальных программах функции работы с памятью могут чаще, чем кажется, прощать ошибки. MM>Это знаешь, как на красный иногда можно проехать. Можно, конечно. И временами действительно удобно. Но именно из-за таких решений в свою пользу и появляются ошибки. Решил ты, что здесь goto удобен, Вася Пупкин тоже решил в свою очередь, а потом и Баба Марья написала такую фигню в другом месте. И оба-на! Теперь у вас куча goto в проекте, написанные разными людьми. Потому и говорят: не пиши goto. Вот просто не пиши и всё.
Если всех ровнять под одну гребенку и огульно запрещать всё что может привести к ошибкам, то получим бредовый и неадекватный coding style. Я видел как goto-ненавистники лепили мега-монстра с кучей хитровложенных ифов, do-while и свитчей только для того чтобы правильно выйти из нескольких циклов. Там без бутылки не поймешь когда и куда оно выходит, лучше бы написали goto.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, Dimonka, Вы писали:
D>Здравствуйте, Niemand, Вы писали:
N>>после второго курса любая прога на делфи начиналась у меня с {$O-}. Раз потратил вечер на понимание как в коде D>
D>for i:=0 to 7 do
D> ...
N>>i принимает значение 8, 9 и только потом выходит. А ответ прост как сало без хлеба: баг оптимизации.
D>Если i нигде не используется, то какая разница какое значение i принимает?
Многоточие может означать не только глубину и полет мысли, но и какой-то код, который можно скипнуть в моем случае это был проход по графу, потому зашкаливание i играет таки большую роль
If the message above is in English — means I'm wasting my work time and work computer to post here. No hard feelings
Re: Как важно проверять в программах ошибки до конца
M>Мораль в качестве выводов:
M>1) Если есть ошибка полезно докопаться до ее истоков, а не просто избавиться от нее. M>2) Можно обнаружить что-то для себя новое в казалось бы давно и хорошо известном.
Мораль тут совсем иная. Нужно знать, как работают базовые конструкции языка, на котором пишешь. Мне лень лезть в делфевые доки(никогда с делфями не работал), но что-то мне подсказывает, что в них черным по белому написано, как ведет себя finally.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, djs_, Вы писали:
_>Не в качестве сарказма, а действительно любопытно — 2ALL: а где нибудь есть иное поведение?
Нигде не видел. Да и какой тогда смысл в finally? Этот конструкция специально придумана для того, чтобы гарантированно выполнить определенные действия, что бы ни случилось внутри блока.
_>И можно как нибудь вывернуться и это переопределить, скажем, на Java?
Именно в java на уровне языка и компилятора — никак. Можно изменить скомпиленный байткод, но это грязный хак.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, Vladek, Вы писали:
V>Здравствуйте, carpenter, Вы писали:
C>>я както во фрискейле работал — так у них там с одной игрушкой типа волка ловящего яйца, C>>гдето на 14 часу игры проскакивал глюк .
не все ошибки проверяемы до конца
Весь мир — Кремль, а люди в нем — агенты
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, carpenter, Вы писали:
C>Здравствуйте, Vladek, Вы писали:
V>>Здравствуйте, carpenter, Вы писали:
C>>>я както во фрискейле работал — так у них там с одной игрушкой типа волка ловящего яйца, C>>>гдето на 14 часу игры проскакивал глюк .
C>не все ошибки проверяемы до конца
Если пользователь не обнаружил ошибки, то можно считать, что её и нет.
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, мыщъх, Вы писали:
L>>> для кого юнит-тесты эквивалентны занятию ерундой, срочно сменить профессию. L>>> Других мнений по этому поводу быть не может. М>>а вы тесты писали? насколько серьезно подходили к процессу их разработки? L>Почему в прошедшем времени?
потому что русский язык такой. в английском было бы Present Perfect Tense --> опыт есть: да/нет
L>Остальное поскипано как очередная история очередного ниасилинга L>с кучей оправданий одно другого убедительнее. Обсуждения не заслуживает.
а вы осилите тест факториала? хотя бы на уровне псевдокода? если да, то почему вы не миллионер?
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, Dolios, Вы писали:
D>Здравствуйте, мыщъх, Вы писали: М>> программист, который писал функцию факториала был не в курсе что такое факториал вообще и очень сильно удивился, когда _все_ калькуляторы считали факториалы дробных чисел. программист сказал, что они все идиоты и едут по встречной, а он находится в своем ряду. D>А можно для тупых поподробней. Я всегда считал, что факториал определён только для целых неотрицательных чисел. Гамма функция это какбы не совсем факториал.
русскую вику не читал, английская не только говорит, что факториал определен для дробных, но даже объясняет как его считать. если писать в одну строчку и наплевать на точность, то будет примерно так:
#define E 2.71828182845904523536
#define PI 3.14159265358979323846
возьмите факториал от дроби и сравните с виндовым калькулятором. ну или с любым он-лайн калькулятором (вдруг это ошибка виндового калькулятора), вот первая ссылка в гугле: http://www.calculator-tab.com/
факториал часто используется в статистике и там он часто бывает дробным. факториал для целых чисел это школьный курс. школьный курс + факультатив -- там задачки взять факториал дробного числа.
другой вопрос, что нормальному программисту факториал брать приходится прямо скажем нечасто. и это хорошая иллюстрация, что и гугл не поможет, если нет фундаментальной базы.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Я иногда кое-что пишу или отлаживаю на Delphi или FreePascal (не только на них и вообще это не так важно). Сегодня отлаживал одну ошибку, программа почему-то падала. Выяснил, что падение возникает из-за ошибок в некоторых данных (это другая история), которые программа забывала проверить на корректность. Добавил проверку. Можно было бы успокоиться, что все заработало, но решил выяснить, из-за чего она все-таки падала при неправильных данных.
M>Это меня ошарашило. Я несмотря на то, что казалось бы имею давний опыт программирования на Delphi еще с 90-х годов и иногда периодически что-то писал, не знал, что exit внутри try...finally вызывает не немедленный выход из функции, а переход к блоку finally. Думал, что этот блок исполняется только в нормальном случае или при исключениях, а exit немедленно завершает функцию. Ошибался. Теперь удивляюсь, как же я умудрился раньше не нарваться на ошибки в этом месте (дважды вызов Free например из-за этого)
M>Мораль в качестве выводов:
M>1) Если есть ошибка полезно докопаться до ее истоков, а не просто избавиться от нее. M>2) Можно обнаружить что-то для себя новое в казалось бы давно и хорошо известном.
Из своего опыта:
Если был глюк, и после не понятных телодвижений он исчез, жди глюка снова.
Если был глюк, и понятно откуда у него ноги растут, то ноги отрываем и наслаждаем отсутствием глюка.
Re[8]: Как важно проверять в программах ошибки до конца
Здравствуйте, linuz, Вы писали:
L>Здравствуйте, мыщъх, Вы писали:
М>>Здравствуйте, linuz, Вы писали:
L>Я вам про фому, а вы мне про ерему. Вы как раз про тот случай когда автор кода толком не понимает чего он от своего кода хочет. А я про то, что юниттесты нужны чтобы не отвалилось что-то что раньше точно работало.
так ведь отвалится. и сейчас я объясню почему.
L>unsigned long factorial(int n) L>{ L> static const unsigned long fact_tab[13] = { L> 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600 L> }; L>Вариант безглючный и самотестирующийся.
извините, но вы самоуверенный мракобес. при очередной оптимизации программы функцию факториала перепишут и она начнет его считать быстро, но приближенно. весьма вероятный сценарий развития событий. и тут ваш тест провалится, хотя функция будет работать.
но даже если исходить из допущения, что оптимизация не влечет потерю точности, то у вас таблица все равно не правильная. ну ладно, заполняли от балды. бывает. меня вот что интересует -- с каких это пор размер int'а стал строго определенным? или вы никогда не писали программу под 2+ платформы сразу? если int у нас 64 бита (а такое возможно), то тут нужно сначала посмотреть какой у нас int на данной конкретной платформе, а уже потом выбирать под него таблицу. а если int 16 бит (такое тоже бывает), то ваш тест снова выстрелит мимо.
писать тест, который работает только в паре с определенным компилятором и под определенную платформу с определенными опциями компиляции -- на фига? вот перекомпилировали код и ваш тест показал ошибку. а ошибка не в коде, а в тесте. крысота.
> Если понадобится факториал дабла, отрицательных чисел, натуральных дробей, и.т.д, > то буду делать по учебнику, применяя подходящие к случаю типы данных.
пытаюсь объяснить еще раз. в реальной жизни куча функций типа факториала считается приближенно, ибо точный результат зачастую менее важен, чем скорость вычислений. проблема даже не в том, чтобы вычислить 100000! (можно и по таблице), проблема в том -- как хранить такой большой bignum и что с ним делать.
а приближенные вычисления это такая область, в которой очень трудно что либо тестировать, ибо нужен эталон, а эталона нету, но есть (скажем) библиотечная функция, которая так же считает приближенно. сравнивать два приближенных значения -- нельзя, ибо мы не знаем в какую сторону у нас отклоение в каждом конкретном случае.
да, и еще. совсем забыл. время вычислений -- вполне себе метрика. нормальный тест должен проверять -- не впадает ли функция в нирвану глубокой задумчивости минут на полчаса. возьме тот же винкалк. при всей его простоте он предлагает остановится или считать дальше, т.к. в противном случае в однопоточных приложениях нельзя даже закрыть окно -- все повисло нахрен. у вас есть такая проверка? а она нужна. потому что после изменений программа может впасть в дурной цикл и никогда не завершится. элементарно, ватсон, кто-то напишет while(1); и привет обкому. вы же не руками запускаете каждый тест, верно? у вас же это автоматизировано. вот вы запустили тесты и пошли курить. вернулись и... балин. оно повисло. логи-то есть? а если есть, то был ли сброшен дисковый буффер перед входом в цикл?
это я не к тому, что юнит тесты не нужны. это я к тому, что сложность написания теста зачастую сильно превышает сложность написания кода. в вашем тесте больше ошибок, чем в коде. и этот тест создает проблемы на ровном месте, которые не возникают когда этого теста нет.
"ошибка не в коде, а в тесте" -- это классика тестирования. тест показывает ошибку и если (ну вы же такой самоуверенный), считать, что тест безглючный, то можно долго искать черную кошку в черной комнате и только потом написать тест для проверки корректности теста...
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>>>а вы тесты писали? насколько серьезно подходили к процессу их разработки? L>>Почему в прошедшем времени? М>потому что русский язык такой. в английском было бы Present Perfect Tense --> опыт есть: да/нет
Двойка тебе. Как по русскому, так и по английскому. В контексте обсуждения на русском нужно использовать настоящее "вы тесте пишете?", а на английском present continous "are you writing unit tests (at all)?".
L>>Остальное поскипано как очередная история очередного ниасилинга L>>с кучей оправданий одно другого убедительнее. Обсуждения не заслуживает. М>а вы осилите тест факториала? хотя бы на уровне псевдокода? если да, то почему вы не миллионер?
При всем уважении, ты пытаешься лезть в область, в которой нихрена не понимаешь. Это я про тестирование. Я даже не знаю, с чего начать, чтобы объяснить глубину твоего заблуждения, и считаю, что будет просто честным предложить оставаться тебе в своем хакерском R&D мире и не лезть в инженерные задачи в своих латексных перчатках. У нас требуются сертифицированные перчатки другой системы, и несоблюдение техники безопасности бывает фатальным.
Списывание отсутствия тестов на недостаточность ресурсов — это безоговорочное признание в собственной некомпетентности и прямая путевка за кассу в Макдональдс. Ситуация, описанная топикстартером, тому доказательство. Написать тест, проверяющий поведение его супер-функции при корректных, некорректных и граничных вхожных данных заняло бы две минуты. Ладно, это у меня. У ТС — ну полчаса максимум. Сколько у него там на отладку ушло времени? Вот то-то и оно.
Далее, факториал, точнее, то, что принято называть факториалом, на C++ вычисляется в compile time. Его можно тестировать, но смысла особого нет. Но и твою притянутую за уши реализацию гамма-функции я тоже протестирую, но при одном условии — если ты асилишь обозначить четкие критерии ее использования в программе, ее предназначение, ограничения и ожидаемое поведение. Если этого нет, то разочарую тебя — прикладной аналитикой занимаются на другом этаже.
L> Написать тест, проверяющий поведение его супер-функции при корректных, некорректных и граничных вхожных данных заняло бы две минуты. Ладно, это у меня. У ТС — ну полчаса максимум. Сколько у него там на отладку ушло времени? Вот то-то и оно.
Тогда немного опишу, что же именно некорректного было в данных. У меня функция заносит в БД извлеченное и обработанное содержимое некоторых файлов внутри *.zip -файлов, при этом естественно проверяет на корректность и само содержимое обрабатываемых файлов и формат и тд. При этом в редких случаях внутри *.zip-файла может быть еще вложенные *.zip-файлы и их тоже надо распаковать и в свою очередь проверить, что внутри. Вложенный файл я обрабатывал просто рекурсивным вызовом.
Тесты (просто набор разных исходных данных) есть, все ситуации с ошибками тестировали и они обрабатывались, программа не падала.
Но забыли протестировать случай, когда такая ошибка возникает при работе с содержимым внутри вложенного файла. То есть, неправильная работа с exit не приводила почему-то к падениям, пока работа шла на первом уровне вложенности. Я и говорю, что диспетчер памяти оказался склонным прощать некоторые ошибки в работе с ней. Падать стало внутри рекурсии.
Программу я уже не трогал с год, просто все это время не случалось такого редкого сочетания с ошибкой.
Re[8]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, мыщъх, Вы писали:
М>>потому что русский язык такой. в английском было бы Present Perfect Tense --> опыт есть: да/нет L>Двойка тебе. Как по русскому, так и по английскому. В контексте обсуждения на русском нужно L>использовать настоящее "вы тесте пишете?", а на английском present continous L>"are you writing unit tests (at all)?".
единица вам. "are you writing..." вы пишите тест _одновременно_ с чтением форума. вы юлий цезарь?
Present Perfect Tense переводится как "вы _когда_ _либо_ писали тесты?". по аналогии I've been in London. это отличается от I was in London. в первом случае это "у меня есть жизненный опыт и я знаю что такое Лондон не только по картинкам", во втором случае вы просто там были. например, вас спрашивают -- какого хрена вас вчера не было на рабочем месте. а вы отвечаете: I was in London.
L> При всем уважении, ты пытаешься лезть в область, в которой нихрена не понимаешь. L> Это я про тестирование. Я даже не знаю, с чего начать, чтобы объяснить глубину
с критическими инфраструктурами я не сталкивался и как там тестируют по — хз, но энерпрайз и военка -- это для меня ежедневная рутина. показывать им юнит тесты все равно что показывать палец. юмора не поймут и слив защитан.
повторяю еще раз -- тест должен _доказать_ полноту и непротиворечивость. преобразование программы в диаграмму типа flow chart с последующей верификацией позволяет _доказать_, что она корректна (тут кажется кто-то упоминал светофор в качестве примера, кажется в контексте дракона. существуют системы верификации по, доказывающие, что два зеленых света гореть не могут. а доказать это можно если перевести ваш юнит в fsm, но это не юнит тест, это _совсем_ другое).
> У нас требуются сертифицированные перчатки другой системы > и несоблюдение техники безопасности бывает фатальным.
ваша пися больше моей? хорошо, давайте возьмем линейку, какими ISO вы руководствуетесь? понимаете, юнит-тест это сугубо ваше личное (можно даже сказать интимное) дело. никому кроме вас он на хрен не нужен и не интересен. когда будете сдавать продукт серьезному заказчику (банку, скажем) от вас потребуют совсем других тестов. какая там техника безопасности, о чем вы? есть формальные требования, вы им следуете. строите формальные модели.
еще раз. снимите розовые очки. посмотрите хотя бы на ошибки в ракетной технике, ошибки в медицинском оборудовании... при этом комплексы по тестированию этого самого оборудования это отдельные проекты. почитайте книгу inside intel -- там описано как параллельно с разработкой цп разрабатывались системы их тестирования. почитайте статью "редкая профессия" о том как писался компилятор и параллельно с ним писались тесты другой группой девов и сравните их бюджеты.
L> Списывание отсутствия тестов на недостаточность ресурсов — это безоговорочное L> признание в собственной некомпетентности и прямая путевка за кассу в Макдональдс.
пытаюсь объяснить еще раз -- сложность _полного_ теста намного превышает сложность того, что мы тестируем. откроейте глаза и посмотрите на то, что вас окружает. начиная с программного обеспечения и заканчивая медикаментами. далеко не все это тестируется, а если и тестируется, то неполно и поверхностно. ракетно-космическая техника тестируется лучше, чем гражданская авиация, а гражданская авиация тестируется лучше, чем бытовой софт. а если бытовой софт тестировать по полной программе, то это все равно не гарантирует отсутствие ошибок, но цена ms office перевалит за миллиард баксов за одну лицензию. что вы курили?
> Сколько у него там на отладку ушло времени? Вот то-то и оно.
был бы отладочная печать -- было бы видно, где оно падает. но отладочной печати у него нету. а что мне делать если я аппаратно-программный комплекс разрабатываю? концепция интерактивной отладки к нему вообще не применима. даже логгировать нельзя в силу определенных ограничений (требования к сертификации -- отсутствие винта, а память не резиновая, ее и так мало и в случае краха системы в памяти ничего не будет, а если бы и было...)
L> Далее, факториал, точнее, то, что принято называть факториалом, на C++ вычисляется в compile time.
см. определение из вики. см. функцию факториала из гну либы на gcc.
L> Его можно тестировать, но смысла особого нет.
поздравляю. вы произнесли заветные слова. "тестировать можно, но на хрена?". то есть по факту вы со мной согласны, но при этом делаете вид, что один из нас дурак, хотя мы оба говорим, что юнит-тест написать можно, но смысла в этом нет.
L> Но и твою притянутую за уши реализацию гамма-функции я тоже протестирую,
она не моя. она из 18 века вообще-то. а сейчас 21 век. столько не живут ИМХО.
L> но при одном условии — если ты асилишь обозначить четкие критерии ее использования в программе,
лопата! вот у вас есть библиотечная гамма-функция. а она у вас есть (если под никсы пишите). и у вас возникает вопрос -- как быстро она работает? насколько сильно ошибается? вы хотите знать подходит ли она вам или нет. у вас есть требования по точности и времени. известны и целевые платформы. дело за малым -- убедиться, что все воркается. и вот тут выясняется, что тестирование функции которая заведово работает выливается в сложную инженерную задачу...
L> Если этого нет, то разочарую тебя — прикладной аналитикой занимаются на другом этаже.
вот он -- момент просветления. на уровне юнит-теста вы не можете сказать какие у вас требования к данной функции. допустим, время отклика системы должно быть не хуже 15 ms на таком-то железе. это во всей совокупности.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, alzt, Вы писали:
A>Здравствуйте, newCL, Вы писали:
CL>>объясните идиоту, пожалуйста, CL>>как можно использовать try...finally и не знать как оно работает? A>Можно знать как работает finally, можно знать как работает exit. Но можно не знать как они работают вместе. У кого, так сказать, приоритет.
проблема несколько глубже. результаты уже на лице -- в жабе стало нельзя легально прибивать потоки без участия с их стороны. допустим, мы вызвали скрипт манагер из жабы, который вызывает жаба-скрипт, контролируемый юзером/хакером. допустим, в жаба-скрипте while(1); -- в результате поток висит. легально снять -- нельзя. нелегально можно, но это уже хак.
так же есть расширения для руби и питона, позволяющие вызывать движок google v8. и у большинства нет легальных механизмов отвалиться по тайм-ауту. как ни странно у фокса этот муханизм есть. точнее был. сейчас к нему прикрутили JIT и оно перестало работать (раньше интерпретатор байт-кода тупо считал итерации).
если брать обработку исключений в венде, то там можно обнаружить два уровня. первый уровень -- это когда стек уже кончился, но запас по прочности еще есть. в этом момент выбрасывается нормальное исключение о том, что стека нет (на самом деле есть, но мало). фишка в том, что повторно это исключение уже не вызываается и когда стек заканчивается, то он заканчивается, а обработчик исключений требует стека для себя любимого, а стека у нас нет. в XP в этом случае винда вела себя... мягко говоря не совсем так, как описано в документации. процесс умирал в ядре без освобождения ресурсов (точнее, с негарантированным их освобождением). в семерке уже пофиксили это и добавили (грубо говоря) еще один уровень "finally" (в кавычках, потому что finally пришел из плюсов, но его концепция намного шире) и теперь у нас есть (грубо говоря) процедура аварийного завершения процесса (ядерная) и процедура аврального аварийного завершения процесса. разница между ними в том, что одна из них _гарантирует_ выполнение finally, а другая всего лишь намеревается это сделать.
как бы наивно предполгать, что try...finally работает. оно не работает. оно лишь предполагает. а бог располгает. библиотечные функции, родные для данной системы, скорее всего, придерживаются try...finally (если в спецификации не оговорено обратное), но как поведет себя произвольная функция -- сказать нельзя, особенно если эта функция древняя и оставлена только для совместимости.
короче, лучше не использовать конструкции языка, которых не знаешь.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[8]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, мыщъх, Вы писали:
L>При всем уважении, ты пытаешься лезть в область, в которой нихрена не понимаешь. Это я про тестирование. Я даже не знаю, с чего начать, чтобы объяснить глубину твоего заблуждения, и считаю, что будет просто честным предложить оставаться тебе в своем хакерском R&D мире и не лезть в инженерные задачи в своих латексных перчатках. У нас требуются сертифицированные перчатки другой системы, и несоблюдение техники безопасности бывает фатальным.
Мне, на самом деле, давно интересно собрать статистику, сколько раз regression unit tests вылавливало ошибки, сколько раз после успешного тестирования ошибки все равно обнаруживались и сколько раз test failures ловили ошибки кода, а не теста.
Потому что в теории это классная вещь — написали тесты и теперь никто не изменит так, что оно перестанет работать. В практике я ни разу еще не видел, чтобы это работало. Создание хороших тестов работа более трудозатратная, сложная и высококвалифицированная нежели создание самого кода для бизнес логики. Но даже с хорошими тестами все равно ошибки возможны. И затраты на поддержание онных достаточно велики.
Там где высокая надежность важна, применяются совем другие методы тестирования. Обычно этим занимается отдельная группа людей.
Но даже в более менее обычных бизнес-приложениях грамотный QA по фактору количество пойманных багов и количеству затраченных ресурсов работает значительно эффективней юнит тестов.
Это наблюдения из практики как она есть — никаких теорий.
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, Deprivator, Вы писали:
D>>>программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С D>>>сорри, ниче личного, но это реально факт.
HS>>Знаете, ничего личного, но, например, я, с высоты 11+-летнего опыта промышленной разработки на целой куче императивных языков, не вижу принципиальной разницы между дельфи, крестиками, джавой, шарпом, и чем-бы то ни было ещё императивным.
D>между тем она есть. и даже не в самом языке дело.
Вот видите! Не в языке.
D>дельфи создает иллюзию простоты,
Там не иллюзия простоты, там (на момент конца 90-х и начала нулевых) -- неиллюзорная простота разработки нативных оконных приложений под Windows.
Microsoft к такой простоте формоклепания пришёл значительно позже. Значительно. Если вообще пришёл.
То, что в системе язык-библиотека-среда программирования есть простота -- это плохо?
D>там низкий порог вхождения,
1. Это плохо?
2. Там, между тем, гораздо проще выстрелить себе в ногу, чем, например, в C#. Не в этом дело.
D>типичный дельфист — это формошлеп, слабо представляющий внутреннее устройство системы со всеми отсюда вытекающими последствиями. D>разумеется, про всех не говорю, говорю про тенденцию.
В самом верху не ваша ли цитата? У вас там квантор всеобщности стоит.
D>лет 10 назад мне довелось отсмотреть кучу (больше сотни) мелких проектов, сделанных разными людьми; больше половины из них на дельфи.
Я тоже как раз 10 лет назад поддерживал кучу дельфийского говнокода. Качество кода говорит только о его авторе, но не об использованых средствах разработки.
D>статистика однозначная — сделанное на дельфи очень сильно проигрывает тому же С++.
О дааа. Предлагаю сравнить VCL, сделанную людьми и для людей на дельфи, и MFC, которую, видимо, завезли с Марса. Такое о ней, во всяком случае, сложилось впечатление.
Впрочем, нет. Не предлагаю. Холивар уже разгорается, а в спец. олимпиадах мне участвовать неинтересно.
Сама IDE Delphi написана на Delphi, и уж что-что, а формочки клепать на ней куда как удобнее, чем в VS. То есть, по крайней мере по параметру удобства клепания формочек (==проектированию и программированию оконного интерфейса), дельфи впереди VS. И что теперь?
Впрочем, должен сказать, что Delphi я не видел уже лет шесть. Говорят, там есть новые плюшки типа дженериков и перегрузки операторов, но это я не в курсе. Ибо если ты работаешь с железом и пишешь дрова, выбора, на чём писать, у тебя нет.
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, Niemand, Вы писали:
N>Здравствуйте, Michael7, Вы писали:
N>
N>for i:=0 to 7 do
N> ...
N>
N>i принимает значение 8, 9 и только потом выходит. А ответ прост как сало без хлеба: баг оптимизации.
Т.е. цикл итерируется больше 8-ми раз? Такого не встречал.. А вот по поводу "i" после цикла, помню что в таком коде в турбо-паскале она бы равнялась 7-ми, что исключало возможность использовать её значение. В Delphi, вроде как, ситуацию исправили, но при попытке использования выдаётся warning...
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, linuz, Вы писали: L> Я видел как goto-ненавистники лепили мега-монстра с кучей хитровложенных ифов, do-while и свитчей только для того чтобы правильно выйти из нескольких циклов. Там без бутылки не поймешь когда и куда оно выходит, лучше бы написали goto.
А нечего было так глубоко залазить
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, SingleUseAccount, Вы писали:
SUA>Здравствуйте, linuz, Вы писали: L>> Я видел как goto-ненавистники лепили мега-монстра с кучей хитровложенных ифов, do-while и свитчей только для того чтобы правильно выйти из нескольких циклов. Там без бутылки не поймешь когда и куда оно выходит, лучше бы написали goto.
SUA>А нечего было так глубоко залазить
То есть, чтобы не использовать goto теперь надо еще и от вложенных циклов отказаться?
Re[3]: Как важно проверять в программах ошибки до конца
CL>>объясните идиоту, пожалуйста, CL>>как можно использовать try...finally и не знать как оно работает?
A>Можно знать как работает finally, можно знать как работает exit. Но можно не знать как они работают вместе. У кого, так сказать, приоритет.
Ну, в доках явы, скажем, все описано в паре строчек:
The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
И эта ссылка первая по запросу "java finally". Так что можно прочитать только два первых предложения, чтобы понять суть.
Случаи с прерыванием потока или всего предложения описаны еще двумя предложениями ниже.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[9]: Как важно проверять в программах ошибки до конца
Здравствуйте, Fantasist, Вы писали:
F>Здравствуйте, landerhigh, Вы писали:
L>>Здравствуйте, мыщъх, Вы писали:
F> Мне, на самом деле, давно интересно собрать статистику, сколько раз regression unit tests вылавливало ошибки, F> сколько раз после успешного тестирования ошибки все равно обнаруживались и сколько раз test failures F> ловили ошибки кода, а не теста.
зачем ее собирать, когда она и так есть? http://www.cvedetails.com/ -- пища для размышлений. и ведь во всех этих компаниях есть целые подразделения, занимающиеся исключительно тестированием с нехилым таким бюджетом. а что на выходе? _абсолютно_ _ничего_ работающего хотя бы на 90%. это не значит, что тесты бесполезны. это значит, что на практике ошибки приходится фиксить _после_ релиза на стадии пуско-наладки. причем, эта вполне законная стадия, которой не избежал ни один проект.
F> В практике я ни разу еще не видел, чтобы это работало.
+500. товарищ привел тест, неявно подразумевающий, что у него int 32 бита. очень "полезный" тест, да.
даже если не брать факториал ( это все-таки матчасть ), а взять функцию сортировки, то даже в этом случае трудоемкость написания теста и его объем раз в сто больше. следовательно, в сто раз больше вероятность допустить ошибку в тесте.
при этом далеко не все поддается тестированию. если модуль работает с железом, то все. кранты. даже если железо -- проц. на блоге ms можно найти инфу о том, как проц генерил ошибку доступа к памяти в инструкции типа mov eax, ebx. в ms долго курили очень хорошую траву пока их не торкнуло, что крэш дамп памяти извлекается из памяти. а исключение генерит уже декодированная инструкция глубоко в недрах ЦП, который разогнан сцука и потому там совсем не то, что ожидалось.
уже смешно? а если вы поставляете аппаратно-программный комплекс и он падает под нагрузкой только потому что не расчитан на такую температуру (типа флорида). вы тестируете его на аляске -- и у вас все хокей. ошибка упорно не воспроизводится. кто виноват? железо? а если часть программного комплекса автоматически снижает тактовую частоту при перегреве? а что если при снижении тактовой частоты нагрузка на проц увеличивается, т.к. увеличивается время вычислений, а потому он еще сильнее разогревается? и что увеличение таковой частоты как раз ведет к охлаждению, т.к. процу появляется время на остановится, соснуть и охладиться.
> Создание хороших тестов работа более трудозатратная, сложная и высококвалифицированная > нежели создание самого кода для бизнес логики. Но даже с хорошими тестами все равно > ошибки возможны. И затраты на поддержание онных достаточно велики.
в том-то и дело, что написать парсер, скажем, XML раз в 100500 раз проще, чем написать тест этого парсера. в обоих случаях требуются глубокие знания XML. если их нет, то парсер написать еще можно и он будет как бы работать, а вот написать для него тест и _доказать_ полноту теста -- это высший пилотаж. и на практике применяется другой подход. берут "живые" данные и смотрят на реакцию парсера. если на каком-то файле парсер падает -- юзер сабмитит этот файл в саппорт и там уже разбираются. это -- реальная жизнь.
тесты пишутся тогда и только тогда, когда вероятная цена ошибки превышает затраты на разработку тестов. если убытки от ошибки близки к нулю -- дешевле фиксить баги по мере их выявления. в противном случае тесты удорожают программу, но не обеспечивают никаких конкурентных преимуществ. если у среднестатистического юзера программа не падает, то юзер видит разницу только в цене и недоумевает зачем платить больше, когда и так работает. мы же не говорим про программы для пилотирования ядерных бомбардировщиков -- к ним совсем иные требования.
F> Но даже в более менее обычных бизнес-приложениях грамотный QA по фактору F> количество пойманных багов и количеству затраченных ресурсов работает F> значительно эффективней юнит тестов.
кстати, огромное кол-во ошибок вылезает на стыке разных модулей. интеграционные тесты рулят. и не только тесты. я уже писал про формальные модели и разные диаграммы состояний, наличие которых зачастую обязательное требование к проекту. без диаграмм состояний его просто не примут.
так же я писал про файл-бомбы нового поколения, где архиватор распаковывает архив с циклическими симлинками. а вот попытка архивации/бэкапа этой директории приводит к бесконечному рекурсивному спуску и краху. протестировав большое кол-во архиваторов и программ бэкапа, а так же утилит и программ пакетной обработки файлов я удивился -- в среднем из 100 программ только 1 проходит этот простой и банальный тест из чего я делаю вывод, что функцию обхода дерева каталогов вообще не тестировали, а если и тестировали, то в сферических условиях.
F>Это наблюдения из практики как она есть — никаких теорий.
в том-то и дело, что тесты -- не панацея. а юнит тесты это как целые числа на фоне всех прочих. и гордится тем, что у нас есть юнит тесты это все равно, что говорить "а я умею считать до ста тысяч миллионов".
чтобы что-то тестировать нужно иметь формальную модель этого самого того, что мы тестируем. а ее обычно нет. даже на примере парсера XML. ну есть спецификации разных версий, а есть ПО, генерирующее XML. часто бывает так, что ПО, генерирующее XML, являющийся нашими входными данными, противоречит спецификациям, но это ПО нам неподконтрольно. а заказчику класть на спецификации. ему нужно, чтобы две программы работали вместе, понимая друг друга.
тут кончается теория и начинается реальная жизнь. тест XML парсера, написанный по науке -- бесполезен, ибо парсер падает на "живых" данных, о которых тест и не подозревает. и в чем ценность такого теста? а если взять программу на JavaScript, то как ее тестировать юнит-тестами, если нам нужно, чтобы она нормально работала на всех браузерах? тестировать -- нужно. но не юнит тестами.
в реальной жизни основная нагрузка ложится на QA. они, в частности, проверяют, что в коде нет ошибок типа SQL-injection и вообще тестируют все, что только можно протестировать. а если у нас есть QA, то зачем вкладываться в юнит-тесты? да, конечно, юнит тесты бывают полезны местами, чтобы отлавливать наиболее грубые ошибки. но тут главное не перестараться и не вложить в юнит тест больше времени и сил чем нужно.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[8]: Как важно проверять в программах ошибки до конца
SUA>>Здравствуйте, linuz, Вы писали: L>>> Я видел как goto-ненавистники лепили мега-монстра с кучей хитровложенных ифов, do-while и свитчей только для того чтобы правильно выйти из нескольких циклов. Там без бутылки не поймешь когда и куда оно выходит, лучше бы написали goto.
SUA>>А нечего было так глубоко залазить
M>То есть, чтобы не использовать goto теперь надо еще и от вложенных циклов отказаться?
Ну, вообще-то, желательно. Вложенные циклы без вынесения внутреннего в отдельную функцию, весьма трудночитаемы.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>проблема несколько глубже. результаты уже на лице -- в жабе стало нельзя легально прибивать потоки без участия с их стороны. допустим, мы вызвали скрипт манагер из жабы, который вызывает жаба-скрипт, контролируемый юзером/хакером. допустим, в жаба-скрипте while(1); -- в результате поток висит. легально снять -- нельзя. нелегально можно, но это уже хак.
Что в данном случае означает "вызвали скрипт манагер из джавы"? Ну, то есть, что есть скрипт манагер? Если это жабовкий класс, и он не имеет штатных методов остановки, то это не скрипт-манагер, а кусок говна. Если это внешний процесс, то остановить его очень легко.
М>если брать обработку исключений в венде, то там можно обнаружить два уровня. первый уровень -- это когда стек уже кончился, но запас по прочности еще есть. в этом момент выбрасывается нормальное исключение о том, что стека нет (на самом деле есть, но мало). фишка в том, что повторно это исключение уже не вызываается и когда стек заканчивается, то он заканчивается, а обработчик исключений требует стека для себя любимого, а стека у нас нет. в XP в этом случае винда вела себя... мягко говоря не совсем так, как описано в документации. процесс умирал в ядре без освобождения ресурсов (точнее, с негарантированным их освобождением). в семерке уже пофиксили это и добавили (грубо говоря) еще один уровень "finally" (в кавычках, потому что finally пришел из плюсов, но его концепция намного шире) и теперь у нас есть (грубо говоря) процедура аварийного завершения процесса (ядерная) и процедура аврального аварийного завершения процесса. разница между ними в том, что одна из них _гарантирует_ выполнение finally, а другая всего лишь намеревается это сделать.
М>как бы наивно предполгать, что try...finally работает. оно не работает. оно лишь предполагает. а бог располгает. библиотечные функции, родные для данной системы, скорее всего, придерживаются try...finally (если в спецификации не оговорено обратное), но как поведет себя произвольная функция -- сказать нельзя, особенно если эта функция древняя и оставлена только для совместимости.
В жабе проще. Там стек-то не нативный, и исключение полетит и обработается в любом случае(не тобой, так штатным обработчиком, установленным для этого потока, по умолчанию это вывод трейса в stderr). Потому можно не париться техническими трудностями: для исключения стека всегда хватит.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, Deprivator, Вы писали:
D>дельфи создает иллюзию простоты, там низкий порог вхождения, типичный дельфист — это формошлеп, слабо представляющий внутреннее устройство системы со всеми отсюда вытекающими последствиями.
Однажды, очень давно, довелось мне написать это:
function ClipperCRC(const Stream: TStream): Cardinal;
label
ReadLoop, DataLoop, ProcEnd;
var
CPU: packed record
SI, DI, BP: Word;
DS: array[1..512] of Byte;
case Byte of
0: (AL, AH, DL, DH, BL, BH, CL, CH: Byte);
1: (AX, DX, BX, CX: Word);
2: (AXDX, BXCX: Cardinal);
end;
begin
Stream.Position:= 0;
with CPU do
begin
BP:= 0;
DI:= 0;
ReadLoop:
CX:= SizeOf(DS);
AX:= Stream.Read(DS, CX);
if AX = 0 then goto ProcEnd;
DI:= DI+AX;
CX:= AX-1;
SI:= 1;
AX:= 0;
DataLoop:
AX:= AX+PWord(@DS[SI])^; // add AX, [DS:SI]
Inc(SI);
if CX > 1 then// loop DataLoopbegin
Dec(CX);
goto DataLoop;
end
else
CX:= 0;
BP:= BP+AX;
AL:= DS[SI];
AH:= DS[SI];
Inc(SI);
BP:= BP+AX;
AX:= BP;
DX:= DI;
AXDX:= AX*DX; // mul DX
BP:= BP+AX;
if BP = 0 then Inc(BP);
goto ReadLoop;
ProcEnd:
DX:= DI;
AX:= BP;
end;
Result:= CPU.AXDX;
end;
Откуда взялся этот код и почему он выглядит именно так, должно быть понятно любому здесь. Расскажите неграмотному дельфисту что-нибудь про формошлепство и непонимание внутреннего устройства компьютера.
Re[5]: Как важно проверять в программах ошибки до конца
Здравствуйте, Eugeny__, Вы писали:
E__>Здравствуйте, мыщъх, Вы писали:
E__>Что в данном случае означает "вызвали скрипт манагер из джавы"?
я пытался решить эту проблему и тут одно из двух -- или я туплю или проблема не имеет решения в рамках норм приличия.
берем код вида:
ScriptEngine js = new ScriptEngineManager().getEngineByName("js");
FileReader f = new FileReader(args[0]); js.eval(f); f.close();
считаем, что в файле может быть 'while(1);' или какие другие подлянки. наша задача -- выполнить скрипт или спустя 500 ms послать скрипт на юг и вернуть ошибку, освободив все ресурсы.
> Если это внешний процесс, то остановить его очень легко.
это ScriptEngineManager из JRE. его можно остановить без ругательств со стороны компилятора? я пробовал и так, и сяк -- компилятор выдает предупреждение, что и то, и се уже давно как deprecated и потому такое решение не пропускает QA (и правильно делает).
E__>В жабе проще. Там стек-то не нативный, и исключение полетит и обработается в любом случае
ну не знаю. в дизассемблере четко вижу, что значительная часть библиотечных функций написана на нативном коде и выполняется на нативном процессоре. и если полетит нативный стек... в руби и питоне все тоже самое. пока мы пишем код на самом языке -- нам гарантируют отсутствие неожиданностей. как только вызываем из питона модуль, написанный на си, -- тут питон уже бессилен.
и потому я вполне могу вообразить ситуацию, когда вызов super_lib.super_exit(0) вызовет API оси, а ось не знает, что мы должны выполнить какой-то код перед завершением. вся надежда на автора библиотеки super_lib. надежда, как вы понимаете, слабая. пример тому -- ошибки переполнения нативного стека в штатных библиотеках. если авторы java так косячат, чего ожидать от каких-то студентов, пишуших библиотеки в гараже у которых даже QA нет.
> Потому можно не париться техническими трудностями: для исключения стека всегда хватит.
лень вспоминать cve номер ошибки переполнения стека. нативного. кажется в 2008 или в 2009 году нашли. там короче когда вызывается апплет и создается поток и переполняется стек, то выскакивает исключение, которое ловится и подавляется. затем стек переполняется еще раз. на этот раз винда уже убрала сторожевую страницу и выскакивает или исключение доступа или мы врезаемся в стек другого потока. так из одного потока можно воздействовать на стек другого. а к чему это приводит... теоритически можно лихо подменять практически любые данные. практически хакеры не ушли дальше крэша. но это потому что на тот момент в хакерскую индустрию еще не хлынули миллионы криминальных долларов и никому было не интересно реализовать атаку на банк клиент, например.
java, как ни крути, исполняется на нативном стеке. и java-машина не свободна от ошибок. давайте зададимся вопросом -- что произойдет, если выполнение библиотечной функции приведет к переполнению нативного стека? и как java-программист может обработать такую ситуацию или предотвратить ее? на винде в нативном си коде я могу. даже очень могу. я просто поставлю свою сторожевую страницу, зарезервировав для своих нужд пол-метра памяти. это хватит с головой, чтобы корректно обработать любую ситуацию -- сделать откат или по крайней мере сохранить все данные и корректно завершиться. и мне наплевать на библиотеки. пускай делают, что хотят. навряд ли кто-то полезет в стек искать "левую" сторожевую страницу и специально ее снимать (это уже умышленное вредительство).
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[5]: Как важно проверять в программах ошибки до конца
Здравствуйте, quwy, Вы писали:
Q>Здравствуйте, Deprivator, Вы писали:
Q>Откуда взялся этот код и почему он выглядит именно так, должно быть понятно любому здесь. Q>Расскажите неграмотному дельфисту что-нибудь про формошлепство и непонимание внутреннего устройства компьютера.
извините, но у вас ноги из попы растут. код непортабельный. мрак. по нормальному должен быть тормозной портабельный код на паскале и асм-модули под разные платформы. кстати, код на паскале если писать по уму не такой уж и тормозной даже с учетом отсутствия оптимизации у компилятора.
программы на дельфи я узнаю сразу. в них хронически не работает tab или скачет между полями не в том порядке в котором они на экране. дельфисты не читают гайдлайнов. когда я такое увидел на webmoney, то с этой конторой мне сразу стало все ясно. это октябрята, которых не взяли в пионеры. удивительно, но в среде того же ms vs такое встречается значительно реже и tab'ы работают как надо. не потому что это среда обеспечивает (не обеспечивает она этого), а потому что порог вхождения выше.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, Eugeny__, Вы писали:
E__>Здравствуйте, alzt, Вы писали:
E__>The finally block always executes when the try block exits.
см. выделенное. вы не анализировали малварь на java. там хорошая традиция -- не выполнять finally, перепрыгивая через него. кстати, делается легально средствами самой java без всяких там хаков. декомпиляторы с ума сходят -- control flow хрен построишь.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
Q>>Откуда взялся этот код и почему он выглядит именно так, должно быть понятно любому здесь. Q>>Расскажите неграмотному дельфисту что-нибудь про формошлепство и непонимание внутреннего устройства компьютера. М>извините, но у вас ноги из попы растут.
Ваше мнение озвучено, но отвергнуто как несостоятельное. До свидания.
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, quwy, Вы писали:
Q>Здравствуйте, мыщъх, Вы писали:
Q>>>Откуда взялся этот код и почему он выглядит именно так, должно быть понятно любому здесь. Q>>>Расскажите неграмотному дельфисту что-нибудь про формошлепство и непонимание внутреннего устройства компьютера. М>>извините, но у вас ноги из попы растут. Q>Ваше мнение озвучено, но отвергнуто как несостоятельное. До свидания.
обосновать сможете? ну или давайте письками меряться. если мой код на паскале будет работать сильно медленнее вашего асма -- считайте, что у вас длинеее. и, соответственно, наоборот. код тот же что и у вас (по функционалу), компилятор -- аналогично. незнание матчасти, незнание принципов построения осей и компиляторов и прочего фундаментализма не позволяет вам решать задачи на паскале без тормозов.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[8]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>>>извините, но у вас ноги из попы растут. Q>>Ваше мнение озвучено, но отвергнуто как несостоятельное. До свидания. М>обосновать сможете?
Весь ваш пост построен на эмоциях, а не на здравом смысле. Вы не поняли ни задачи, породившей данный код, ни его назначения. Вы сделали необоcнованные заявления. И вообще, вы сильно разочаровали, Николай. Похоже вы больше пиарщик, чем айтишник.
Я не собираюсь ни с кем меряться пиписьками и соревноваться в скорости программ, результаты моего давнего кодинга есть мой сегодняшний доход, и он меня полностью устраивает.
Re[9]: Как важно проверять в программах ошибки до конца
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, landerhigh, Вы писали:
L>> Написать тест, проверяющий поведение его супер-функции при корректных, некорректных и граничных вхожных данных заняло бы две минуты. Ладно, это у меня. У ТС — ну полчаса максимум. Сколько у него там на отладку ушло времени? Вот то-то и оно.
M>Тогда немного опишу, что же именно некорректного было в данных. У меня функция заносит в БД извлеченное и обработанное содержимое некоторых файлов внутри *.zip -файлов, при этом естественно проверяет на корректность и само содержимое обрабатываемых файлов и формат и тд. При этом в редких случаях внутри *.zip-файла может быть еще вложенные *.zip-файлы и их тоже надо распаковать и в свою очередь проверить, что внутри. Вложенный файл я обрабатывал просто рекурсивным вызовом.
Ой, уже звучит страшно. Не слишком ли много для одной функции? Хотя, если она внутри выглядит примерно так
то все еще пучком.
M>Тесты (просто набор разных исходных данных) есть, все ситуации с ошибками тестировали и они обрабатывались, программа не падала.
Не все. Не удивлюсь, если знаменитая mail-бомба в зипе также способна свалить вашу программу. Да тут еще и рекурсия, подуснет какой дятел поврежденный или специально подготовленный зип с тучей уровней вложенности и привет переполнение стека.
M> Но забыли протестировать случай, когда такая ошибка возникает при работе с содержимым внутри вложенного файла. То есть, неправильная работа с exit не приводила почему-то к падениям, пока работа шла на первом уровне вложенности. Я и говорю, что диспетчер памяти оказался склонным прощать некоторые ошибки в работе с ней. Падать стало внутри рекурсии.
привычка писать юнит-тесты доводит до того, что программист органически становится неспособным "забыть" протестировать такие. То есть написать тест, покрывающий подобную ситуацию воспринимается как нечто само собой разумеющееся и никаких вопросов не вызывает.
Кроме того, написать юнит-тест, проверяющий корректность работы и непадучесть этой функции, примерно в 10 тысяч раз легче, нежели тестировать ее корректное поведение на этапе QA. И выгоднее.
M>Программу я уже не трогал с год, просто все это время не случалось такого редкого сочетания с ошибкой.
М>единица вам. "are you writing..." вы пишите тест _одновременно_ с чтением форума. вы юлий цезарь? М>Present Perfect Tense переводится как "вы _когда_ _либо_ писали тесты?". по аналогии I've been in London. это отличается от I was in London. в первом случае это "у меня есть жизненный опыт и я знаю что такое Лондон не только по картинкам", во втором случае вы просто там были. например, вас спрашивают -- какого хрена вас вчера не было на рабочем месте. а вы отвечаете: I was in London.
здесь. Дальше распространяться на эту тему не буду, но даже по-русски будет корректнее спросить "а пишете ли вы вообще тесты", потому что любое прошедшее время подразумевает, что тесты писали, и, возможно, прекратили.
L>> При всем уважении, ты пытаешься лезть в область, в которой нихрена не понимаешь. L>> Это я про тестирование. Я даже не знаю, с чего начать, чтобы объяснить глубину М>с критическими инфраструктурами я не сталкивался и как там тестируют по — хз, но энерпрайз и военка -- это для меня ежедневная рутина. показывать им юнит тесты все равно что показывать палец. юмора не поймут и слив защитан.
Еще раз — ты пытаешься рассуждать на тему, в которой нихрена не понимаешь. Юнит-тест — это инструмент разработки. Его клиентам не показывают. Игнорирование этого мощного инструмента разработки привело к тому, что ТС пришлось убить кучу времени на пошаговую отладку. Я бы вообще отбирал у программистов отладчик на время разработки.
М>повторяю еще раз -- тест должен _доказать_ полноту и непротиворечивость. преобразование программы в диаграмму типа flow chart с последующей верификацией позволяет _доказать_, что она корректна (тут кажется кто-то упоминал светофор в качестве примера, кажется в контексте дракона. существуют системы верификации по, доказывающие, что два зеленых света гореть не могут. а доказать это можно если перевести ваш юнит в fsm, но это не юнит тест, это _совсем_ другое).
Это ты сейчас с кем разговариал? И, пожалуйста, не упоминай конечные автоматы в суе и особенно в разговорах со мной. Порву на лоскуты размером в атом, а из того, что осталось, вызову цепную ядерную реакцию.
>> У нас требуются сертифицированные перчатки другой системы >> и несоблюдение техники безопасности бывает фатальным. М>ваша пися больше моей? хорошо, давайте возьмем линейку, какими ISO вы руководствуетесь? понимаете, юнит-тест это сугубо ваше личное (можно даже сказать интимное) дело. никому кроме вас он на хрен не нужен и не интересен. когда будете сдавать продукт серьезному заказчику (банку, скажем) от вас потребуют совсем других тестов. какая там техника безопасности, о чем вы? есть формальные требования, вы им следуете. строите формальные модели.
К счастью, никакое ISO не регламентирует, как именно должны тестироваться элементы ПО. И опять же, не путай UAT и FAT c тестированием во время разработки. Ты можешь построить хоть стопицот формальных моделей, потратить полгода на FAT и успешно пройти его, и все равно можешь жидко обосраться на второй день после запуска в эксплуатацию. Доказательство элементарно — твой софт состоит сплошь из функций, которые принимают какие-то входные значения, что-то с ними делают и выдают результат. Утрировано, конечно, но это так. Каждая их таких функций имеет следующие подмножества входных параметров — корректные, некорректные и граничные. Тебе, помимо функционального тестирования (проверить, что функция делает именно то, что должна), нужно проверить корректность поведения этой функции на этих наборах параметров. То есть на каждую функцию нужно еще три теста (три набора тестов, если быть точным, но в данном контексте это неважно). Соответственно, если у тебя 1000 функций, то тебе понадобится 3000 тестов, по грубой оценке.
Но! Если ты забъешь на юнит-тестирование, и будешь пытаться тестировать всю систему целиком как чОрный йащег (с), то тебе для достижения того же уровня покрытия, критериев этих и собственно, тест кейсов, понадобится минимум 3^1000. Удачи, как говорится, и заодно слив защитан.
М>еще раз. снимите розовые очки. посмотрите хотя бы на ошибки в ракетной технике, ошибки в медицинском оборудовании... при этом комплексы по тестированию этого самого оборудования это отдельные проекты. почитайте книгу inside intel -- там описано как параллельно с разработкой цп разрабатывались системы их тестирования. почитайте статью "редкая профессия" о том как писался компилятор и параллельно с ним писались тесты другой группой девов и сравните их бюджеты.
Дорогой, ты только что привел примеры двух индустрий, где юнит-тестирование проводится практически везде. Изготовление электронных компонентов, например. Каждый из них тестируется на сходе с конвеера. Каждая плата проходит электрический тест. Каждая собранная плата проходит как минимум базовый функциональный тест до установки ее в систему. Тестирование осуществляется на каждом этапе, где это только возможно автоматизировать. Там, где автоматизировать поленились или ошиблись с определением критериев, отрастают проблемы. То, что все равно есть ошибки — это всего лишь результат сложности системы. Если бы производители резисторов не тестировали их, то никакой ракетной техники бы не было вообще.
L>> Списывание отсутствия тестов на недостаточность ресурсов — это безоговорочное L>> признание в собственной некомпетентности и прямая путевка за кассу в Макдональдс. М>пытаюсь объяснить еще раз -- сложность _полного_ теста намного превышает сложность того, что мы тестируем. откроейте глаза и посмотрите на то, что вас окружает. начиная с программного обеспечения и заканчивая медикаментами. далеко не все это тестируется, а если и тестируется, то неполно и поверхностно. ракетно-космическая техника тестируется лучше, чем гражданская авиация, а гражданская авиация тестируется лучше, чем бытовой софт. а если бытовой софт тестировать по полной программе, то это все равно не гарантирует отсутствие ошибок, но цена ms office перевалит за миллиард баксов за одну лицензию. что вы курили?
Уважаемый, ты заговариваешься. Военная ракетная техника изначально тестировалась исключительно на полигоне. Но все очень быстро поняли, что, во-первых, восстанавливать полигон после каждого неудачного запуска не хватит ни одного военного бюджета, а, во-вторых, выяснять, что именно пошло не так, имея в наличии лишь оплавленный и спекшийся песок полигона, не очень продуктивно. Именно поэтому ракетные двигатели тестируются на стендах. И вся их обвязка тоже. Это и есть юнит-тестирование. Это, конечно, не узбавляет от катастроф на 100%, но уменьшает их вероятность на много порядков.
>> Сколько у него там на отладку ушло времени? Вот то-то и оно. М>был бы отладочная печать -- было бы видно, где оно падает. но отладочной печати у него нету. а что мне делать если я аппаратно-программный комплекс разрабатываю? концепция интерактивной отладки к нему вообще не применима.
Я тебе посоветую не разрабатывать программно-аппаратный комплекс, так как из твоих слов понятно, что ты в этой теме ни бум-бум.
L>> Далее, факториал, точнее, то, что принято называть факториалом, на C++ вычисляется в compile time. М>см. определение из вики. см. функцию факториала из гну либы на gcc.
L>> Его можно тестировать, но смысла особого нет. М>поздравляю. вы произнесли заветные слова. "тестировать можно, но на хрена?". то есть по факту вы со мной согласны, но при этом делаете вид, что один из нас дурак, хотя мы оба говорим, что юнит-тест написать можно, но смысла в этом нет.
Нечего там тестировать, ибо в никакого кода в рантайм не попадает. Написать тест, проверяющий корректность вычисления, конечно, нужно, но это настолько тривиально, что не стоит обсуждения.
L>> Но и твою притянутую за уши реализацию гамма-функции я тоже протестирую, М>она не моя. она из 18 века вообще-то. а сейчас 21 век. столько не живут ИМХО.
L>> но при одном условии — если ты асилишь обозначить четкие критерии ее использования в программе, М>лопата! вот у вас есть библиотечная гамма-функция. а она у вас есть (если под никсы пишите). и у вас возникает вопрос -- как быстро она работает? насколько сильно ошибается? вы хотите знать подходит ли она вам или нет. у вас есть требования по точности и времени. известны и целевые платформы. дело за малым -- убедиться, что все воркается. и вот тут выясняется, что тестирование функции которая заведово работает выливается в сложную инженерную задачу...
Тебе про Фому, а ты про Ерему.
L>> Если этого нет, то разочарую тебя — прикладной аналитикой занимаются на другом этаже. М>вот он -- момент просветления. на уровне юнит-теста вы не можете сказать какие у вас требования к данной функции. допустим, время отклика системы должно быть не хуже 15 ms на таком-то железе. это во всей совокупности.
L>>При всем уважении, ты пытаешься лезть в область, в которой нихрена не понимаешь. Это я про тестирование. Я даже не знаю, с чего начать, чтобы объяснить глубину твоего заблуждения, и считаю, что будет просто честным предложить оставаться тебе в своем хакерском R&D мире и не лезть в инженерные задачи в своих латексных перчатках. У нас требуются сертифицированные перчатки другой системы, и несоблюдение техники безопасности бывает фатальным.
F> Мне, на самом деле, давно интересно собрать статистику, сколько раз regression unit tests вылавливало ошибки, сколько раз после успешного тестирования ошибки все равно обнаруживались и сколько раз test failures ловили ошибки кода, а не теста.
Такой статистики не существует. Потому что, с одной стороны, есть группы, умеющие правильно использовать юнит-тестирование, и с другой стороны, если ниасилившие. А базиса и методологии для сравнения результатов их работы не существует по очевидным причинам.
Большой плюс итеративного юнит-тестирования вообще и TDD в частности состоит в том, что многие ошибки, котроые программистам свойственно допускать, оказываются не допущенными еще на этапе написания кода.
F> Потому что в теории это классная вещь — написали тесты и теперь никто не изменит так, что оно перестанет работать. В практике я ни разу еще не видел, чтобы это работало. Создание хороших тестов работа более трудозатратная, сложная и высококвалифицированная нежели создание самого кода для бизнес логики. Но даже с хорошими тестами все равно ошибки возможны. И затраты на поддержание онных достаточно велики.
Нет никаких затрат на поддержание тестов. Если они есть, вы что-то делаете неправильно. Это мое профессиональное мнение, основанное на десятках коммерческих проектов.
F> Там где высокая надежность важна, применяются совем другие методы тестирования. Обычно этим занимается отдельная группа людей.
Нет смысла тестировать надеждность лифтов в небоскребе, если строители не могут точно сказать, какой марки бетон залит в основание фундамента этого небоскреба.
F> Но даже в более менее обычных бизнес-приложениях грамотный QA по фактору количество пойманных багов и количеству затраченных ресурсов работает значительно эффективней юнит тестов.
Никогда не путай QA и юнит-тестирование. Их задачи разные. Использовать QA для отлова того, что должно было быть протестировано юнит-тестом равносильно стрельбе из пушки по комарам.
F>Это наблюдения из практики как она есть — никаких теорий.
Моя наблюдения из практики почему-то своершенно другие.
Вот моги главные замеченные отличие проектов, написанных в стиле "тесты писать некогда, нужно копать" от тех, где тесты, и много, были написаны:
1. проекты, где юнит-тестирование применялось првильно и в полный рост, чаще всего оказываются code complete и feature complete еще до дедлайна, в то время, как проекты без юнит-тестирования без исключений залезают крепко за дедлайн
2. Ошибки, найденные во время QA на проектах, покрытых юнит-тестами, разительно отличаются от ошибок, найденных на классических проектах. Обычно они лежат в плоскости "а мы считаем, что здесь спеки требуют другого поведения" и "поведение соответствует спекам, но заказчик понял, что ошибся в спеках и поэтому поведение нужно изменить", в то время как багрепорты от QA на классических проектах пестрят "упало", "не работает вообще", "сожрало всю память и опять упало" и прочими WTF.
3. Проекты, покрытые юнит-тестами, намного более гибкие в смысле дальшейшего развития и обеспечивают возможность легкого рефакторинга.
4. Из юнит-тестов можно вычленять автоматические функциональные тесты, облегчая работу QA
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, мыщъх, Вы писали:
L>здесь. Дальше распространяться на эту тему не буду,
и что там по ссылке? и где я там не прав?
L> но даже по-русски будет корректнее спросить "а пишете ли вы вообще тесты",
"вы тесты писали" --> "занимались ли вы когда либо написанием тестов". что не так?
L> потому что любое прошедшее время подразумевает, что тесты писали, и, возможно, прекратили.
возможно и прекратили. возможно и нет. но если писали, то опыт остался даже если прекратили.
L> Еще раз — ты пытаешься рассуждать на тему, в которой нихрена не понимаешь.
это не аргумент. тоже самое я могу сказать о вас.
L> Юнит-тест — это инструмент разработки. Его клиентам не показывают.
привести примеры когда показывают? из того, что доступно в иннете? так кто из нас двоих ни хрена не понимает?
L> Игнорирование этого мощного инструмента разработки привело к тому, L> что ТС пришлось убить кучу времени на пошаговую отладку. Я бы вообще L> отбирал у программистов отладчик на время разработки.
согласен на счет отладчика. не согласен на счет теста. отладочная печть и логи -- чем не вариант?
L> И, пожалуйста, не упоминай конечные автоматы в суе и особенно в разговорах со мной. L> Порву на лоскуты размером в атом, а из того, что осталось, вызову цепную ядерную реакцию.
стадию перехода на личности мы уже миновали и вот уже добрались до прямых угроз. давайте, рвите. мне и правда интересно
L> К счастью, никакое ISO не регламентирует, как именно должны тестироваться элементы ПО.
у него еще и номер круглый. если вы хоть однажды в него заглядывали, то должны помнить.
L> Доказательство элементарно — твой софт состоит сплошь из функций,
кто-то обещал порвать меня на автоматы. интересно, сколько у нас функций в DFA-дереве?
L> которые принимают какие-то входные значения, что-то с ними делают и выдают результат. L> Утрировано, конечно, но это так. Каждая их таких функций имеет следующие подмножества L> входных параметров — корректные, некорректные и граничные.
_каждая_ ?! вы в этом уверены?! функций без аргументов уже не бывает? my_pi() — какие тут аргументы? даже утрированно? какие некорректные аргументы у функции abs?!
L> То есть на каждую функцию нужно еще три теста (три набора тестов, если быть точным, L> но в данном контексте это неважно). Соответственно, если у тебя 1000 функций, L> то тебе понадобится 3000 тестов, по грубой оценке.
вы снова соглашаетесь со мной, что исчерпывающий тест намного больше по объему кода и по трудоемкости написания, чем то, что он тестирут. модели для других целей строят. например, если это пульт управления микроволновой печи -- модель _доказывает_, что нельзя войти в меню из которого потом не выйти. именно, что _доказывает_, причем верификация осуществляется автоматически.
L>Дорогой, ты только что привел примеры двух индустрий, L>где юнит-тестирование проводится практически везде.
и обе индустрии вбухивают в тестирование мегабабло. потому что цена ошибки дороже.
М>>был бы отладочная печать -- было бы видно, где оно падает. но отладочной печати у него нету. а что мне делать если я аппаратно-программный комплекс разрабатываю? концепция интерактивной отладки к нему вообще не применима.
L>Я тебе посоветую не разрабатывать программно-аппаратный комплекс, L>так как из твоих слов понятно, что ты в этой теме ни бум-бум.
кто-то грозился отобрать отладчик...
L> Сейчас ты лезешь в розетку с амперметром.
сколько слов, наездов, самоуверенности и при этом никаких возражений по существу. вы говорите, что юнит тесты нужны. ок, допустим это так. осталось только оценить расходы на их разработку и заложить их в бюджет.
вы так и не ответили на вопрос -- как убедиться в том, что в тесте нет ошибок?
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>Здравствуйте, landerhigh, Вы писали:
L>>Здравствуйте, мыщъх, Вы писали:
L>>здесь. Дальше распространяться на эту тему не буду, М>и что там по ссылке? и где я там не прав?
Пункт 2.
L>> но даже по-русски будет корректнее спросить "а пишете ли вы вообще тесты", М>"вы тесты писали" --> "занимались ли вы когда либо написанием тестов". что не так?
Не так. Изначально не тот посыл. Некрасивый и заставляет оправдывться. Вроде "вы уже перестали бить свою жену по выходным".
L>> потому что любое прошедшее время подразумевает, что тесты писали, и, возможно, прекратили. М>возможно и прекратили. возможно и нет. но если писали, то опыт остался даже если прекратили.
У 80% тех, у кого опыт остался, но прекратили, опыт этот сугубо отрицательный. Потому что писали из-под палки и только потому, что заставлял менеджер.
L>> Еще раз — ты пытаешься рассуждать на тему, в которой нихрена не понимаешь. М>это не аргумент. тоже самое я могу сказать о вас.
Все приведенные тобой примеры не имеют никакого отношения к прадигме и предназначению юнит-тестирования.
L>> Юнит-тест — это инструмент разработки. Его клиентам не показывают. М>привести примеры когда показывают? из того, что доступно в иннете? так кто из нас двоих ни хрена не понимает?
показывают, когда клиент явно просит, чего тут непонятного?
L>> Игнорирование этого мощного инструмента разработки привело к тому, L>> что ТС пришлось убить кучу времени на пошаговую отладку. Я бы вообще L>> отбирал у программистов отладчик на время разработки. М>согласен на счет отладчика. не согласен на счет теста. отладочная печть и логи -- чем не вариант?
Сравниваешь теплое с мягким. Тесты выполяются автоматически во время каждого билда, и отладочная печать и логи по сравнению с ними находятся в одином ряду с каменным топором по сравнению с современным станком с ЧПУ.
L>> И, пожалуйста, не упоминай конечные автоматы в суе и особенно в разговорах со мной. L>> Порву на лоскуты размером в атом, а из того, что осталось, вызову цепную ядерную реакцию. М>стадию перехода на личности мы уже миновали и вот уже добрались до прямых угроз. давайте, рвите. мне и правда интересно
А вот не надо было соскользывать с темы и приплетать FSM куда не надо.
L>> К счастью, никакое ISO не регламентирует, как именно должны тестироваться элементы ПО. М>у него еще и номер круглый. если вы хоть однажды в него заглядывали, то должны помнить.
Этот ISO — он для менеджеров. Которые программировать не умеют.
L>> Доказательство элементарно — твой софт состоит сплошь из функций, М>кто-то обещал порвать меня на автоматы. интересно, сколько у нас функций в DFA-дереве?
Я нигде не говорил, что я телепат.
L>> которые принимают какие-то входные значения, что-то с ними делают и выдают результат. L>> Утрировано, конечно, но это так. Каждая их таких функций имеет следующие подмножества L>> входных параметров — корректные, некорректные и граничные. М>_каждая_ ?! вы в этом уверены?! функций без аргументов уже не бывает? my_pi() — какие тут аргументы? даже утрированно? какие некорректные аргументы у функции abs?!
Хорошо, какой-то процент функций явных аргументов иметь не будет. Зато половина из них будет иметь контекст (глобальный или своего объекта), и зависимости от него тоже нужно тестировать.
А про abs(float) можешь начинать считать лоскуты. Граничные и специальные условия:
1) Проверка поведения при -0
2) проверка поведения при обоих NaN
3) Проверка, что никакой чертовщины с потерей точности не происходит
Это то, что пришло мне в голову за одну секунду.
L>> То есть на каждую функцию нужно еще три теста (три набора тестов, если быть точным, L>> но в данном контексте это неважно). Соответственно, если у тебя 1000 функций, L>> то тебе понадобится 3000 тестов, по грубой оценке. М>вы снова соглашаетесь со мной, что исчерпывающий тест намного больше по объему кода и по трудоемкости написания, чем то, что он тестирут. модели для других целей строят.
Цитату можно, где я соглашался?
Эти 3000 тестов будут состоять из трех-четырех строчек каждый; трудоемкость их написания на фоне затрат на разработку основного кода незаметна, а объем — вообще странная метрика. Более того, факт написания тестов оказывает положительный эффект на разработку собственно кода, поскольку тестируемый код должен удовлетворять критериям тестируемости, которые магическим образом совпадают с обобщенными критериями "хорошести" и "поддерживаемости" кода. Выполнение этих тестов занимает несколько секунд.
Трудоемкость такого подхода совершенно ничтожна по сравнению с затратами, которые потребовались бы на орагнизацию аналогичного по покрытию набора функциональных black-box тестов.
М>например, если это пульт управления микроволновой печи -- модель _доказывает_, что нельзя войти в меню из которого потом не выйти. именно, что _доказывает_, причем верификация осуществляется автоматически.
А вот тут я, как и обещал, порву тебя на лоскуты. Пульт управления микроволновки — это типичный пример state machine. То, что в ней нет тупиков, доказывается в первую очередь диаграммой состояний вашей машины и таблицей переходов. Верифицируется ручками, глазками, и девайсом /dev/brain. Как и все подобные конечные автоматы. А вот после реализации можно и нужно написать функциональный тест, который в том числе проверит, что из каждого меню можно выйти в $HOME.
L>>Дорогой, ты только что привел примеры двух индустрий, L>>где юнит-тестирование проводится практически везде. М>и обе индустрии вбухивают в тестирование мегабабло. потому что цена ошибки дороже.
Знаем мы, куда они мегабабло вбухивают. На бонусы непричастным и сетрификацию некомпетентными.
М>>>был бы отладочная печать -- было бы видно, где оно падает. но отладочной печати у него нету. а что мне делать если я аппаратно-программный комплекс разрабатываю? концепция интерактивной отладки к нему вообще не применима.
L>>Я тебе посоветую не разрабатывать программно-аппаратный комплекс, L>>так как из твоих слов понятно, что ты в этой теме ни бум-бум. М>кто-то грозился отобрать отладчик...
... компилятор тоже надо отобрать. А то ногу себе прострелишь.
Ты имей в виду, я на тебя не наезжаю. Более того, по этому форуму я тебя весьма уважаю, как минимум потому, что для меня то, чем ты занимаешься — это такой темный лес, что я туда даже заглядывать боюсь. Но в данном случае ты залез в ту область, где я уже сожрал почти всех собак. А ты время от времени несешь такую чушь, что я даже не могу найти слов, чтобы ответить.
L>> Сейчас ты лезешь в розетку с амперметром. М>сколько слов, наездов, самоуверенности и при этом никаких возражений по существу. вы говорите, что юнит тесты нужны. ок, допустим это так. осталось только оценить расходы на их разработку и заложить их в бюджет.
Нет никаких особых расходов на разработку этих тестов. Вообще, когда спрашивают о расходах на разработку тестов, это является признаком полного непонимания подхода TDD и использования юнит-тестов в разработке. Этот процесс не разделим на составные части.
Как только разработчик становится адептом церкви TDD на своем опыте узнает преимущество юнит-тестирования, для него юнит-тесты перестают существовать как отдельная сущность. Для нас процесс разработки есть процесс написания собственно кода и кода, его тестирующего. Они неотделимы друг от друга, как неотделимы и наши собственные оценки затрат и как результат, бюджет. Кроме того, наши оценки временных затрат зачастую являются гораздо более точными, так как, прежде чем приступить к estimations, мы должны не только ответить на вопрос "а что мы будем писать", но и "а как мы это будем автоматически тестировать".
И, как правило, мы обычно достигаем результата заметно быстрее. Потому что на каждом этапе мы проверяем корректность только что написанного, и нам не надо для этого заниматься онанизмом в отладчике или вручную ковырять логи. Мы можем верифицировать большинство модулей еще до того, как система дойдет до стадии, когда ее можно будет запустить и проверить в работе. Мы получаем возможность вести разработку итеративно, потому что набор тестов, разработанный нами же, будет оказывать нам неоценимую помощь при рефакторинге.
М>вы так и не ответили на вопрос -- как убедиться в том, что в тесте нет ошибок?
Ошибки в тестах, как правило, ортогональны ошибкам в коде, который они призваны проверять. Опять же, если ошибка в тесте приводит к тому, что тест не проходит, просто вернись и пофикси ее. От ошибок, приводящих к false positive, помогает практика писать negative test cases.
Здравствуйте, landerhigh, Вы писали:
L>здесь. Дальше распространяться на эту тему не буду, но даже по-русски будет корректнее спросить "а пишете ли вы вообще тесты", потому что любое прошедшее время подразумевает, что тесты писали,
давно Present Perfect стало прошедшим? Present как переводится?
Забанен с формулировкой "клинический дисидент".
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, b-3, Вы писали:
b-3>Здравствуйте, landerhigh, Вы писали:
L>>здесь. Дальше распространяться на эту тему не буду, но даже по-русски будет корректнее спросить "а пишете ли вы вообще тесты", потому что любое прошедшее время подразумевает, что тесты писали, b-3>давно Present Perfect стало прошедшим? Present как переводится?
Рассказать, как переводится Perfect?
Это время используется для обозначения действия, завершенного к настоящему моменту без указания конкретного периода в прошлом. То есть "have you done any unit testing at all?" == "писали ли вы тесты когда-либо?". Посыл ложный, о чем я и говорю.
Здравствуйте, quwy, Вы писали:
Q>Однажды, очень давно, довелось мне написать это: Q>Откуда взялся этот код и почему он выглядит именно так, должно быть понятно любому здесь. Расскажите неграмотному дельфисту что-нибудь про формошлепство и непонимание внутреннего устройства компьютера.
кстати да, абсолютно чудовищный код.
In P=NP we trust.
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, SingleUseAccount, Вы писали:
SUA>А нечего было так глубоко залазить
Попал мне как-то древний исходник на xBase (не помню, Fox или Clipper). Автор того кода передачу управления вверх организовывал как раз, запихивая определенные участки кода в WHILE и выставляя в условии хитрые комбинации флажков. И столько этих циклов нагородил, что я тогда впервые пожалел, что goto в xBase предназначен для прыжков по записям в таблице, а не по коду программы. Я раньше прочитал пару строк на Фортране 4, так что макаронами меня запутать было сложнее, чем их эмуляцией.
Re[5]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>Здравствуйте, landerhigh, Вы писали:
L>>Здравствуйте, newCL, Вы писали:
L>> для кого юнит-тесты эквивалентны занятию ерундой, срочно сменить профессию. L>> Других мнений по этому поводу быть не может. М>а вы тесты писали? насколько серьезно подходили к процессу их разработки? у вас была формальная модель, доказывающая корректность, непротиворечивость и полноту теста? сомнительно. и какая польза от теста, который что-то тестирует? конечно, польза есть, но если вы углубитесь в теорию и практику тестирования, то очень быстро убедитесь, что существуют и другие пути.
Перефразируя известную фразу: юнит-тесты только потому писать надо, что они код в порядок приводят. Во-первых для того чтобы покрыть юнит тестами какую-то систему, нужно ее сначало хорошенько структурировать, а это уже плюс. Во-вторых, имхо, юнит тесты не нацелены на отлов всех ошибок. Первоначально они используются для того чтобы убедиться хоть в какой-то работоспособности данного модуля, потом, в случае выявления ошибок, тесты используются для закрепления баг фикса, и дают гарантию, что при последующем изменении кода, данная проблема не вернется незамеченной. Конечно в реальности бывают различные случаи: нет времени, денег, мотивации, нужно чтобы уже вчера работало, тогда конечно можно и без юнит тестов, но это уже не относится к тому как правильно писать код.
М>если вы не согласны и уверены в себе и своих знаниях -- плз, напишите функцию факториала вместе с тестом.
Факториал писать не приходилось, но приходилось писать много других алгоритмов из вычислительной математики и computer science. Без юнит тестов там вообще невозможно написать, хоть какой-то более менее сложный алгоритм.
Re[9]: Как важно проверять в программах ошибки до конца
Здравствуйте, Eugeny__, Вы писали:
E__>Здравствуйте, Michael7, Вы писали:
SUA>>>Здравствуйте, linuz, Вы писали: L>>>> Я видел как goto-ненавистники лепили мега-монстра с кучей хитровложенных ифов, do-while и свитчей только для того чтобы правильно выйти из нескольких циклов. Там без бутылки не поймешь когда и куда оно выходит, лучше бы написали goto.
SUA>>>А нечего было так глубоко залазить
M>>То есть, чтобы не использовать goto теперь надо еще и от вложенных циклов отказаться?
E__>Ну, вообще-то, желательно. Вложенные циклы без вынесения внутреннего в отдельную функцию, весьма трудночитаемы.
Мда, то есть там, где можно было бы написать понятный и обозримый код из десятка строчек с допустим тремя вложенными циклами и элементарными выходами с помощью goto, надо в итоге нагородить или кучи if-ов и флагов для проверки или выносить циклы в отдельные функции, чтобы можно было выходить по exit. А если выходить надо и со второго уровня и с третьего? Отдельные функции и на все это? Хотя exit тоже некошерен
Такая боязнь goto уже на какое-то сектантство в программировании начинает походить.
Re[10]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>чтобы что-то тестировать нужно иметь формальную модель этого самого того, что мы тестируем. а ее обычно нет. даже на примере парсера XML. ну есть спецификации разных версий, а есть ПО, генерирующее XML. часто бывает так, что ПО, генерирующее XML, являющийся нашими входными данными, противоречит спецификациям, но это ПО нам неподконтрольно. а заказчику класть на спецификации. ему нужно, чтобы две программы работали вместе, понимая друг друга.
О, кстати, да. Буквально месяц назад пришлось разбираться с подобной хренью. Есть крутая система, которая выдает по запросам к ней данные в XML-формате. Не знаю, что там курили программисты, которые писали выдачу, но в некоторых случаях XML не то, что валидацию на соответствие DTD не проходят, а они и вовсе некорректные как XML из-за того, что во-первых, там банально знаки < > и & (спецсимволы) в данных представлены как есть. На чем падает извлечение данных стандартными средствами. В итоге пришлось извращаться и делать предобработку, заменяя в нужных местах эти знаки. Причем я заведомо не смог это сделать совершенно безглючным, потому что я не написал полностью свой парсер даже не XML, а того псевдоXML, что приходится обрабатывать. Просто на примерно том наборе данных, что выдается, замена происходит корректно. Тьфу-тьфу Во вторых, иногда этот XML и вовсе имеет пересекающиеся теги. Хорошо еще, что все такие случаи пока что строго определенные — иногда корневой элемент почему-то закрывается раньше предыдущего вложенного. Других вариантов еще не встретилось.
При этом такие глюки примерно в одном XML-файле из 5000 и пока тестировали и принимали в эксплуатацию на некотором множестве опытных все работало без сбоев. Все замечательно.
Re[10]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
M>>Тогда немного опишу, что же именно некорректного было в данных. У меня функция заносит в БД извлеченное и обработанное содержимое некоторых файлов внутри *.zip -файлов, при этом естественно проверяет на корректность и само содержимое обрабатываемых файлов и формат и тд. При этом в редких случаях внутри *.zip-файла может быть еще вложенные *.zip-файлы и их тоже надо распаковать и в свою очередь проверить, что внутри. Вложенный файл я обрабатывал просто рекурсивным вызовом.
L>Ой, уже звучит страшно. Не слишком ли много для одной функции? Хотя, если она внутри выглядит примерно так
Это не одна функция — это одна программка, которая написано мной полностью и никем, кроме меня же не протестирована
L>то все еще пучком.
M>>Тесты (просто набор разных исходных данных) есть, все ситуации с ошибками тестировали и они обрабатывались, программа не падала.
L>Не все. Не удивлюсь, если знаменитая mail-бомба в зипе также способна свалить вашу программу. Да тут еще и рекурсия, подуснет какой дятел поврежденный или специально подготовленный зип с тучей уровней вложенности и привет переполнение стека.
Не проверял на mail-бомбы, собственно если внешняя либа ей подвержена то будет плохо, если нет — просто ошибка вернется. Но это все-таки, утилита для внутренней автоматизации, которую я быстро написал и с год не прикасался к ней, а не серьезный программный продукт.
M>> Но забыли протестировать случай, когда такая ошибка возникает при работе с содержимым внутри вложенного файла. То есть, неправильная работа с exit не приводила почему-то к падениям, пока работа шла на первом уровне вложенности. Я и говорю, что диспетчер памяти оказался склонным прощать некоторые ошибки в работе с ней. Падать стало внутри рекурсии.
L>привычка писать юнит-тесты доводит до того, что программист органически становится неспособным "забыть" протестировать такие. То есть написать тест, покрывающий подобную ситуацию воспринимается как нечто само собой разумеющееся и никаких вопросов не вызывает. L>Кроме того, написать юнит-тест, проверяющий корректность работы и непадучесть этой функции, примерно в 10 тысяч раз легче, нежели тестировать ее корректное поведение на этапе QA. И выгоднее.
Кхм, но вот я ее проверил на обработку ошибок в данных, на обработку вложенных zip-ов, а вот на комплекс, когда и ошибка в данных и данные внутри вложенного zip-а — не догадался, не подумал. По отдельности-то все работало. Более того, ошибки в данных и вообще очень редко встречаются, а такое их сочетание и вовсе вылезло только через год.
M>>Программу я уже не трогал с год, просто все это время не случалось такого редкого сочетания с ошибкой.
L>А сколько еще подобных мест в вашем коде?
Да наверное хватает Просто цели по качеству сверх минимально необходимого не ставилось. Собственно, если бы не мое же заблуждение насчет exit() ошибки бы в итоге и не возникло.
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, Deprivator, Вы писали:
Q>>Однажды, очень давно, довелось мне написать это: Q>>Откуда взялся этот код и почему он выглядит именно так, должно быть понятно любому здесь. Расскажите неграмотному дельфисту что-нибудь про формошлепство и непонимание внутреннего устройства компьютера. D>кстати да, абсолютно чудовищный код.
Еще один. Ладно, объясняю для тех, кто глухо в танке.
1. Этот код выдернут мной из клипперовского exe-шника.
2. Этот код является дословным переложением ассемблерного листинга на Delphi.
3. Сделано именно так для того, чтобы банковские крысы не придрались к реализации.
4. Где тут формошлепство, не подскажете?
И да, этот код, хоть и должен работать только в винде, но тем не менее он совершенно портабелен.
Re[2]: Как важно проверять в программах ошибки до конца
D>программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С D>сорри, ниче личного, но это реально факт.
Статья 29 Конституции Российской Федерации гласит, что
Не допускаются пропаганда или агитация, возбуждающие социальную, расовую, национальную или религиозную ненависть или вражду. Запрещается пропаганда социального, расового, национального, религиозного или языкового превосходства.
Make flame.politics Great Again!
Re[9]: Как важно проверять в программах ошибки до конца
М>так ведь отвалится. и сейчас я объясню почему.
L>>unsigned long factorial(int n) L>>{ L>> static const unsigned long fact_tab[13] = { L>> 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600 L>> }; L>>Вариант безглючный и самотестирующийся.
М>извините, но вы самоуверенный мракобес. при очередной оптимизации программы функцию факториала перепишут и она начнет его считать быстро, но приближенно. весьма вероятный сценарий развития событий. и тут ваш тест провалится, хотя функция будет работать.
А ты еретик. Когда будете считать приближенный факториал, не забудь предупредить, чтобы мы спрятаться успели. А то забрызгает еще ненароком.
М>но даже если исходить из допущения, что оптимизация не влечет потерю точности, то у вас таблица все равно не правильная. ну ладно, заполняли от балды. бывает. меня вот что интересует -- с каких это пор размер int'а стал строго определенным? или вы никогда не писали программу под 2+ платформы сразу? если int у нас 64 бита (а такое возможно), то тут нужно сначала посмотреть какой у нас int на данной конкретной платформе, а уже потом выбирать под него таблицу. а если int 16 бит (такое тоже бывает), то ваш тест снова выстрелит мимо.
Дорогой, на C++ фактораил считается в компайл-тайме при любом размере инта независимо от платформы. Поэтому его и оптимизировать никто не будет.
М>писать тест, который работает только в паре с определенным компилятором и под определенную платформу с определенными опциями компиляции -- на фига? вот перекомпилировали код и ваш тест показал ошибку. а ошибка не в коде, а в тесте. крысота.
Если ты умудришься написать для факториала тест, который работает только на определенном компиляторе под определнной платформой с определенным опциями, то сорвешь бурные продолжительные аплодисменты за самую бесполезную работу года.
М>это я не к тому, что юнит тесты не нужны. это я к тому, что сложность написания теста зачастую сильно превышает сложность написания кода. в вашем тесте больше ошибок, чем в коде. и этот тест создает проблемы на ровном месте, которые не возникают когда этого теста нет.
Еще раз — так говорят только некомпетентные товарищи. Хватит позориться.
Здравствуйте, landerhigh, Вы писали: L>Здравствуйте, b-3, Вы писали: b-3>>Здравствуйте, landerhigh, Вы писали: L>>>здесь. Дальше распространяться на эту тему не буду, но даже по-русски будет корректнее спросить "а пишете ли вы вообще тесты", потому что любое прошедшее время подразумевает, что тесты писали, b-3>>давно Present Perfect стало прошедшим? Present как переводится? L>Рассказать, как переводится Perfect? L>Это время используется для обозначения действия, завершенного к настоящему моменту без указания конкретного периода в прошлом. То есть "have you done any unit testing at all?" == "писали ли вы тесты когда-либо?". Посыл ложный, о чем я и говорю.
И всё же вы неправы — ваше present continious тоже не вполне корректно. Вот страница из очень авторитетной оксфордской грамматики, CGEL.
Cкан страницы
Цитирую:
Habitual progressive.
The professor types his own letters [The habit is permanent]
The professor is typing his own letters while his secretary is ill [The habit is temporary]
Поэтому "I'm writing unit tests" — это означает либо "я пишу в нынешнем проекте, а обычно не пишу" (a temporary habit), или "я прямо сейчас пишу тесты" (the current action).
Обратите также внимание на примечание внизу страницы(!) Там сказано, что наречие вроде always или all the time меняет смысл, поэтому "Are you always writing UT?" — будет понято правильно, а без always — не будет. Как и "Have you always been writing UT" имеет другой смысл, нежели "Have you been writing UT?". По сути, этот нюанс и разрешает ваш спор в пользу Касперского.
"Are you writing unit tests?" может в контексте иметь смысл habitual — например вопрос к подчинённому — "а юнит-тесты на свой код (который ты ещё не не закоммитил), ты пишешь-то?", но это довольно фамильярно. Вне контекста are you writing unit tests будет воспринято как event, т.е. вопрос о состоянии (ты сейчас что делаешь, пишешь юнит-тесты?) или о state, т.е. об должностных обязанностях (какова твоя роль в проекте, тесты пишешь?) — короче говоря, не поймут.
И надо помнить, что мыщъх вообще-то живёт в США и с native-ами общается изрядно, так что предлагаю постановку "единиц по инглишу" друг другу прекратить.
Забанен с формулировкой "клинический дисидент".
Re[2]: Как важно проверять в программах ошибки до конца
Здравствуйте, Deprivator, Вы писали: D>программисты на дельфи — это всегда очень печальное зрелище. хуже только программисты на 1С
Боюсь, что хуже только программисты на AutoHotkey.
Скрытый текст
Сам я не программист, но скрипты иногда здорово выручают. Недавно случайно обнаружил в AutoHotkey_L забавный глюк, о существовании которого даже не подозревал. Мне надо было копировать короткие текстовые строки, состоящие из 1-2 слов, одновременно преобразуя их так, чтобы первая буква в строке становилась заглавной, а все остальные — строчными. Думал использовать банальное решение: вырезаем первый символ и делаем его заглавным, а к нему присоединяем остальные символы, сделанные строчными. Не тут-то было! Как выяснилось, при конкатенации двух строк между ними почему-то вставляется лишний пробел. Пришлось добавить в конец скрипта операцию замены, чтобы убирать этот пробел.
Re[4]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Тем, для кого юнит-тесты эквивалентны занятию ерундой, срочно рекомендуется сменить профессию. На сантехника или там развозчика пиццы. L>Других мнений по этому поводу быть не может.
От задачи таки зависит...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Почему же обидел? Просто за пропущенное юнит-тестирование (убедиться в отсутствии протечек) сантехник, в отличие от криворучки-программиста, может вполне получить неиллюзорных люлей непосредственно от заказчика и порой прямо не доходя до кассы. Отделаться сдавленными матами от коллег, которые потом придут это поддерживать, не выйдет.
при таком взгляде на работу сантехника мотивация смены специальности с программиста на сантехника как-то не просматривается? Или речь о мазохистах?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Как важно проверять в программах ошибки до конца
L>>Это время используется для обозначения действия, завершенного к настоящему моменту без указания конкретного периода в прошлом. То есть "have you done any unit testing at all?" == "писали ли вы тесты когда-либо?". Посыл ложный, о чем я и говорю.
b-3>И всё же вы неправы — ваше present continious тоже не вполне корректно. Вот страница из очень авторитетной оксфордской грамматики, CGEL.
В разговорной речи в оксфордский словарь заглядывать некогда. Именно в разговорной речи present continous зачастую заменяет простое настоящее время самым причудливым образом.
b-3>И надо помнить, что мыщъх вообще-то живёт в США и с native-ами общается изрядно, так что предлагаю постановку "единиц по инглишу" друг другу прекратить.
Никто его за язык не тянул. Он сам на инглиш перепрыгнул, да и кто из нас с ним больше с нейтивыми общается, вопрос тот еще
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, landerhigh, Вы писали:
L>>Тем, для кого юнит-тесты эквивалентны занятию ерундой, срочно рекомендуется сменить профессию. На сантехника или там развозчика пиццы. L>>Других мнений по этому поводу быть не может.
E>От задачи таки зависит...
Абсолютно согласен. Если стоит задача написать очередной "превед мир", то юнит-тесты можно не писать.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, landerhigh, Вы писали:
L>>Почему же обидел? Просто за пропущенное юнит-тестирование (убедиться в отсутствии протечек) сантехник, в отличие от криворучки-программиста, может вполне получить неиллюзорных люлей непосредственно от заказчика и порой прямо не доходя до кассы. Отделаться сдавленными матами от коллег, которые потом придут это поддерживать, не выйдет.
E>при таком взгляде на работу сантехника мотивация смены специальности с программиста на сантехника как-то не просматривается? Или речь о мазохистах?
Позиция сантехника предлагается тем, кто еще не безнадежен и может учиться. Пару раз огребет, глядишь, и научится чему. Остальным же разучивать "свободная касса!"
Здравствуйте, landerhigh, Вы писали:
L>Абсолютно согласен. Если стоит задача написать очередной "превед мир", то юнит-тесты можно не писать.
Есть задачи, где юнит тесты фиг напишешь. Например, это все задачи, в которых правильное поведение системы заранее неизвестно. Например, таким свойством обладают многие программы в AI...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Как важно проверять в программах ошибки до конца
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, landerhigh, Вы писали:
L>>Абсолютно согласен. Если стоит задача написать очередной "превед мир", то юнит-тесты можно не писать.
E>Есть задачи, где юнит тесты фиг напишешь. Например, это все задачи, в которых правильное поведение системы заранее неизвестно. Например, таким свойством обладают многие программы в AI...
Налицо непонимание концепции и предназначения юнит-тестирования. Объяснить или сам догадаешься?
Здравствуйте, Erop, Вы писали:
E>Есть задачи, где юнит тесты фиг напишешь. Например, это все задачи, в которых правильное поведение системы заранее неизвестно. Например, таким свойством обладают многие программы в AI...
Можно конкретный пример, когда правильное поведение системы неизвестно?
Ce n'est que pour vous dire ce que je vous dis.
Re[8]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Налицо непонимание концепции и предназначения юнит-тестирования. Объяснить или сам догадаешься?
Зачем догадываться до общеизвестных вещей?
Есть разные подходы к этому делу, но та секта, к которой принадлежишь ты, просто не умеет программировать иначе, чем с юнит-тестами. Просто адептом твоего направления для того, что бы спроектировать нормальный класс, нужно сначала написать для него тест, типа такая вот спецификация на код. В принципе подход, как подход, не лучше и не хуже других. Но он не единственный возможный, тем не менее.
Просто далеко не во всех программах и далеко не у всех специалистов основную трудоёмкость занимает именно кодирование и проектирование кода, ещё бывает разработка алгоритмов, построение данных всяких хитрых, настройка системы и т. д... И там юнит-тестирование мало полезно. Кроме того есть довольно много программистов, которым вообще не трудно написать какой-то код, основная стоимость разработки в таких проектах вообще не в кодировании сидит, а в других формах разработки...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: Как важно проверять в программах ошибки до конца
DR>Можно конкретный пример, когда правильное поведение системы неизвестно?
Ну торговля на бирже, например, или распознавание речи...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Как важно проверять в программах ошибки до конца
Здравствуйте, Erop, Вы писали:
DR>>Можно конкретный пример, когда правильное поведение системы неизвестно?
E>Ну торговля на бирже, например, или распознавание речи...
Это не конкретно, на таком уровне не составляют юнит тесты. Давай копнём один из этих примеров чуть глубже. Вбиваем в Google Scholar "speech recognition" и выбираем первую прикладную статью: "Minimum Prediction Residual Principle Applied to Speech Recognition". В ней реализуется распознавание слов по следующим шагам:
записывается слово
запись попускается через фильтр низких частот
результат дискретизируется
слово разбивается на части, и в каждой звук моделируется линейной комбинацией последовательных по времени сигналов
звучание любых двух слов сравнивается по линейным коэфициентам
Каждый шаг выполняет сторого определённую функцию, для каждого алгоритма известно правильное поведение.
Пропускаем через фильтр тестовый сигнал: смотрим, остались ли в нём высокие частоты. Пропускаем белый шум, пропускаем нулевой сигнал, итд.
Дискритизируем тестовый сигнал: смотрим, соответствует ли результат эталону.
Моделируем тестовый звук, проверяем точность модели.
Берём простые наборы тестовых коэффицентов, считаем дистанцию на калькуляторе, смотрим, соответствует ли алгоритм расчётам.
Ce n'est que pour vous dire ce que je vous dis.
Re[14]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>В разговорной речи в оксфордский словарь заглядывать некогда. Именно в разговорной речи present continous зачастую заменяет простое настоящее время самым причудливым образом.
Причудливым, т.е. непонятным вам?
L>Никто его за язык не тянул. Он сам на инглиш перепрыгнул, да и кто из нас с ним больше с нейтивыми общается, вопрос тот еще
Забанен с формулировкой "клинический дисидент".
Re[15]: Как важно проверять в программах ошибки до конца
Здравствуйте, b-3, Вы писали:
L>>В разговорной речи в оксфордский словарь заглядывать некогда. Именно в разговорной речи present continous зачастую заменяет простое настоящее время самым причудливым образом. b-3>Причудливым, т.е. непонятным вам?
Причудливым == не описанным в оксфордских словарях.
Это если на секундочку забыть о том, что разговорный английский порой довольно значительно отличается от английского "оксфордского".
Здравствуйте, landerhigh, Вы писали:
DR>>>Можно конкретный пример, когда правильное поведение системы неизвестно?
E>>Ну торговля на бирже, например, или распознавание речи...
L>О майн готт. L>Про распознование речи говорить ничего не буду, но системы для торговли можно и нужно обкладывать тестами чуть более, чем полностью.
Речь тут шла не про юнит-тесты, а про систему, правильное поведение которой не известно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Как важно проверять в программах ошибки до конца
Здравствуйте, Don Reba, Вы писали:
DR>Здравствуйте, Erop, Вы писали:
DR>>>Можно конкретный пример, когда правильное поведение системы неизвестно?
E>>Ну торговля на бирже, например, или распознавание речи...
Ты просил пример системы, а не класса.
Если хочешь класс -- то любой классификатор, например нейросеть...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, Erop, Вы писали:
E>Ты просил пример системы, а не класса. E>Если хочешь класс -- то любой классификатор, например нейросеть...
Но и тут поведение известно и прекрасно тестируется. Нейросеть тоже состоит из набора отдельных алгоритмов. Например, для тестирования классификации устанавливаем тестовые веса и проверяем, правильно ли классифицируются тестовые данные. Для тестирования обучения устанавливает тестовые веса и проверяем правильно ли они изменяются для тестового ввода и вывода. Когда всё так обложено тестами, гораздо приятней заниматься оптимизацией.
Ce n'est que pour vous dire ce que je vous dis.
Re[3]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, AlexGin, Вы писали:
AG>А почему теперь понадобился этот самый exit? AG>В моем понимании, для Windows приложений с оконным GUI такой выход — это анахронизм.
Выход из процедуры/функции, а не программы Программы впрочем тоже, но только, если в запускающем файле записано.
Re[10]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
[...]
DR>Каждый шаг выполняет сторого определённую функцию, для каждого алгоритма известно правильное поведение.
Теоретически всё правильно, но на практике так не получится — это уже доказано опытом. (Даже Гейтс недавно высказывался на эту тему.) Все эти цифро-спектральные методы хороши только для анализа речи того, кто специально говорил для распознавателя и натренирован в таком говорении. В случае же реальной речи огромную долю выполняет контекст и семантический анализ, который ещё не научились формализовывать. Думаю, что коллега Erop имел в виду именно этот аспект.
The God is real, unless declared integer.
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, netch80, Вы писали:
DR>>Каждый шаг выполняет сторого определённую функцию, для каждого алгоритма известно правильное поведение. N>Теоретически всё правильно, но на практике так не получится — это уже доказано опытом.
Впрочем, если речь об *юнит* тестах, то они тут таки возможны, хотя и не на всю логику.
The God is real, unless declared integer.
Re[12]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>зачем ее собирать, когда она и так есть? 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>проблема несколько глубже. результаты уже на лице -- в жабе стало нельзя легально прибивать потоки без участия с их стороны. допустим, мы вызвали скрипт манагер из жабы, который вызывает жаба-скрипт, контролируемый юзером/хакером. допустим, в жаба-скрипте 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>повторяю еще раз -- тест должен _доказать_ полноту и непротиворечивость.
Бред, извините.
Тест ничего не должен и не может _доказать_.
Тест показывает (подтверждает) корректность работы в одном конкретном случае, который автор теста считает показательным для контроля необходимой работоспособности.
Тест принципиально слабее верификации в том, что он не может сделать проверку всех случаев или даже широкого подмножества. Но тест принципиально сильнее верификации в том, что он проверяет не математическую модель, а реальность (пусть даже искусственно ограниченную). Вы можете тысячу раз просчитать, как именно поведёт себя, например, взрывающаяся граната, или организм подопытной мыши на какое-то вещество, и это будет на моделях и покроет не один конкретный случай, а все. Но тест всё равно нужен, чтобы проверить, что модель учла все существенные факторы.
Искусство разработки тестов — в том, чтобы минимальным количеством тестов проверить максимальное количество возможных нарушений. Иногда этому помогают средства вроде анализа путей исполнения, но в остальном это остаётся неформализуемой задачей.
М>еще раз. снимите розовые очки. посмотрите хотя бы на ошибки в ракетной технике, ошибки в медицинском оборудовании... при этом комплексы по тестированию этого самого оборудования это отдельные проекты. почитайте книгу 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Списывание отсутствия тестов на недостаточность ресурсов — это безоговорочное признание в собственной некомпетентности и прямая путевка за кассу в Макдональдс. Ситуация, описанная топикстартером, тому доказательство. Написать тест, проверяющий поведение его супер-функции при корректных, некорректных и граничных вхожных данных заняло бы две минуты. Ладно, это у меня. У ТС — ну полчаса максимум. Сколько у него там на отладку ушло времени? Вот то-то и оно.
Ты даже не знаешь, где там "суперфункция", но уже делаешь вывод. А теперь скажи, почему ты предполагал, что результат срабатывания exit() вообще будет проверяться, если ТС предполагал, что exit() завершает всю программу включая код теста?
L>Далее, факториал, точнее, то, что принято называть факториалом, на C++ вычисляется в compile time.
Я хочу посмотреть, как ты напишешь реализацию на C++ факториала в compile time, когда аргумент станет известен только в run time. Код в студию.
The God is real, unless declared integer.
Re[9]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
М>извините, но вы самоуверенный мракобес. при очередной оптимизации программы функцию факториала перепишут и она начнет его считать быстро, но приближенно. весьма вероятный сценарий развития событий. и тут ваш тест провалится, хотя функция будет работать.
Тест не провалится. Потому что тест рассчитан на функцию, которая считает 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]: Как важно проверять в программах ошибки до конца
Здравствуйте, Don Reba, Вы писали:
N>>Я хочу посмотреть, как ты напишешь реализацию на C++ факториала в compile time, когда аргумент станет известен только в run time. Код в студию.
DR>Посчитать таблицу всех 12 32-битных или 20 64-битных значений факториала не так сложно.
А теперь — для дробных!
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[9]: Как важно проверять в программах ошибки до конца
Здравствуйте, netch80, Вы писали:
N>Ты даже не знаешь, где там "суперфункция", но уже делаешь вывод. А теперь скажи, почему ты предполагал, что результат срабатывания exit() вообще будет проверяться, если ТС предполагал, что exit() завершает всю программу включая код теста?
Не-не, exit() в delphi завершает функцию внутри которой он вызван, а не всю программу. Всю программу завершает только если в главном (dpr) файле вызван.
Re[6]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
м> считаем, что в файле может быть 'while(1);' или какие другие подлянки. наша задача -- выполнить скрипт или спустя 500 ms послать скрипт на юг и вернуть ошибку, освободив все ресурсы.
Это просто фичу не реализовали. Попробуй это: http://htmlunit.sourceforge.net/apidocs/com/gargoylesoftware/htmlunit/WebClient.html#setJavaScriptTimeout%28long%29
м> > Если это внешний процесс, то остановить его очень легко.
Не надо процессы с тредами путать.
м> это ScriptEngineManager из JRE. его можно остановить без ругательств со стороны компилятора? я пробовал и так, и сяк -- компилятор выдает предупреждение, что и то, и се уже давно как deprecated и потому такое решение не пропускает QA (и правильно делает).
в jre далеко не всегда самые хорошие имплементации.
Здравствуйте, Michael7, Вы писали:
N>>Ты даже не знаешь, где там "суперфункция", но уже делаешь вывод. А теперь скажи, почему ты предполагал, что результат срабатывания exit() вообще будет проверяться, если ТС предполагал, что exit() завершает всю программу включая код теста?
M>Не-не, exit() в delphi завершает функцию внутри которой он вызван, а не всю программу. Всю программу завершает только если в главном (dpr) файле вызван.
То есть это аналог return в C и подобных?
Тогда более удивительно незнание его сочетания с finally.
The God is real, unless declared integer.
Re[12]: Как важно проверять в программах ошибки до конца
DR>Но и тут поведение известно и прекрасно тестируется. Нейросеть тоже состоит из набора отдельных алгоритмов. Например, для тестирования классификации устанавливаем тестовые веса и проверяем, правильно ли классифицируются тестовые данные. Для тестирования обучения устанавливает тестовые веса и проверяем правильно ли они изменяются для тестового ввода и вывода. Когда всё так обложено тестами, гораздо приятней заниматься оптимизацией.
беда тут в том, что часто ищут субоптимум, из может быть много, какой конкретно найдётся --
Но обычно это и не важно.
Ты, конечно можешь зафиксировать какой-то поток управления и считать его эталонным. Но тогда не нужны тесты, тогда нужны подробные логи...
Но это сильно ограничит оптимизацию...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: Как важно проверять в программах ошибки до конца
Здравствуйте, Erop, Вы писали:
E>беда тут в том, что часто ищут субоптимум, из может быть много, какой конкретно найдётся -- E>Но обычно это и не важно. E>Ты, конечно можешь зафиксировать какой-то поток управления и считать его эталонным. Но тогда не нужны тесты, тогда нужны подробные логи... E>Но это сильно ограничит оптимизацию...
Проверять надо не какой субоптимум найдётся, а только соответствие реализации алгоритму. То есть, правильно ли обновляются веса, правильно ли расчитываются результаты, итп.
Ce n'est que pour vous dire ce que je vous dis.
Re[14]: Как важно проверять в программах ошибки до конца
DR>Проверять надо не какой субоптимум найдётся, а только соответствие реализации алгоритму. То есть, правильно ли обновляются веса, правильно ли расчитываются результаты, итп.
Не понимаю, что значит "правильно"
Вот что такое правильные веса в узлах нейро-сети, например?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Как важно проверять в программах ошибки до конца
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, мыщъх, Вы писали:
N>Тест не провалится. Потому что тест рассчитан на функцию, которая считает 1) точно, 2) для натурального аргумента, 3) в пределах стандартного int.
стоп. что такое "старндартный int"? стандарт как раз ничего об этом не говорит. вы пишите функцию факториала, а кто-то другой ее компилирует для своей платформы. а если вы тестируете ее исключительно в рамках вашего проекта, то при переходе с 32 на 64 бита -- тест переписывать, т.к. функция работает правильно, а тест проваливается.
N>Для другой постановки задачи будет другое ТЗ и под него изменятся как реализация, так и тест.
даже в рамках этой школьной задачи: ТЗ говорит 'int', стандарт говорит, что int это не обязательно 32 бита и зависит от. в реальной жизни там будет не int, а bignum (из сторонней библиотеки) или плавучка.
N>Под это можно сделать контроль в самом тесте. Если будет в int'е не 32 бита, то на этой платформе тест провалится и будет о чём думать.
тогда возникает вопрос -- что тестирует этот тест? функция же работает на любой платформе. забота о переполнении, очевидно, ложиться на вызывающий код, т.к. в самой функции проверок нет.
это намек на то, что "в лоб" задача тестирования не решается и нужно начинать с провеки какой у нас int.
N>Компилятор и опции тут ни при чём. А затачиваться на 32-битный int сейчас так же нормально, как на реализацию плавучки по IEEE754 или на unix only код.
это ненормально. потому что при портировании кода на архитектуру с другим размером int'а очень нужны юнит тесты, т.к. при портировании лезут косяки. если же косяки лезут из тестов -- на фига нам такие тесты?
N>Надо было взять пример показательнее. Не факториал, а, например, вычисления по RSA.
беретесь написать тест?
N>И как это, по-твоему, вычислительная математика ухитряется чего-то достигать, если там всё такое сложное?
методики тестирования давно разработаны. только сложность тестирования факториала, вычисляемого по функции стирилинга, на порядок сложнее самой этой функции, которая укладывается в одну строку на 80 символов. "порядок" в этом случае -- 10 строк теста. боюсь, что в 10 строк мы не уложимся. в 100 -- может быть. в 1,000 -- однозначно.
вопрос к вам: согласны ли вы, что для факториала, вычисляемого по формуле стирлинга (а это гнутая библиотечная реализация), юнит тест можно заменить интеграционным тестом более высокого уровня. ибо, если у нас косячный факториал, то это это аукнется в использующем его модуле.
аналогично, нужно ли тестировать #define MAX(a,b) ((a>b)?a:b) или нет? формально это неправильный код и жутко багистный. если a и/или b функция с побочными эффектами, то повторный вызов функции может привести к непредсказуемым результатам. то есть по хорошему, чтобы проверить этот макр нужно передать ему функцию с побочными эффектами (или не функцию, а что-то типа MAX(++x, y). кстати, тут ошибка — правильно писать (((a)>(b))?(a)b)), но это все равно неправильно.
тестировать это -- смысла нет. т.к. этот макр изначально ущербный и неполноценный, однако, если он вызывается лишь однажды в стиле x = MAX(PI, E), то все работает.
написать MAX -- дело секунд пяти. протестировать его -- сложная инженерная задача, требующая глубоких знаний си.
М>>да, и еще. совсем забыл. время вычислений -- вполне себе метрика. нормальный тест должен проверять -- не впадает ли функция в нирвану глубокой задумчивости минут на полчаса.
N>С нормальной инфраструктурой подготовки и функционирования тестового окружения — никаких принципиальных проблем.
вы же сами признали, что проблемы есть. функция факториала работает _везде_ (та, которая на интах). хоть на микроконтроллерах, хоть на суперкомпьютерах с необычной архитектурой. при портировании программы, написанной на ANSI C89, на другую платформу, в идеале достаточно перекомпиляции. а по вашему выходит, что она хоть и работает, но тут же валится на всех тестах, и тесты приходится переписывать или... выбрасывать. в этом и есть _принципиальная_ проблема.
N> Количество ошибок в самом тесте минимально.
с учетом того, что программа меньше теста и проще -- ошибок в ней еще меньше.
N> Зачем на понт берёшь, начальник? Нам и так несладко.
вам-то? вам хорошо. у вас есть си и плюсы. они генерируют машинный код, который можно проверить на вашей стороне. а вот веб-дизайнерам тестировать веб-приложения реально несладко.
в скриптовых языках, впрочем, тоже. вот я тут столкнулся, что под питоном мой скрипт работает от 2.4 до 2.7 версий. под pypy возникает течь хэндлов и что за ночь работы скрипта их утекает много тысяч. списался с разработчиками. мне объяснили, что это фича и что сборка мусора у них вообще по другому работает.
вот мне интересно -- как это тестировать? на юнит тесте во-первых очень сложно достучаться до счетчиков оси, считающих хэндлы. во-вторых, сложно разобраться сколько этих хэндлов должно быть. это же питон, блин. он сам знает когда их закрывать. и самое печальное -- юнит тест проходит на ура. вызываем мою функцию много-много раз в цикле и по завершению цикла, pypy видит, что программа подходит к концу и чистит все ресурсы. а потому дебит сходится с кредитом. а в реальной ситуации (да еще когда код вызывается из многих потоков), pypy считает, что чистить ресурсы еще рано.
вообще-то это даже в факе у них написано (что у них такая мегафича), но юнит тест проходит, а интеграционный тест проваливается.
короче, я тут пытаюсь говорить о том, что написание юнит тестов должно быть вдумчивым. прежде чем писать тест нужно взвесить все за и против. наличие юнит-тестов само по себе -- это ни разу не показатель. а бравировать тем, что мы пишем юнит тесты -- вообще смешно. написать тест может и обезьяна. а вот написать корректный и действительно полезный юнит-тест -- это все-таки высший пилотаж.
тесты -- нужны. но тестов много. юнит-тесты это как вилка. кушать ей борщ -- теоритически возможно (выловить капусту и мясо, а жидкость высосать, приложившись к тарелке губами), но практически на этот случай есть ложка. ложки есть даже у китайцев, которые едят палочками.
короче, мне непонятно, почему если тест, то обязательно юнит.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re[15]: Как важно проверять в программах ошибки до конца
Здравствуйте, Erop, Вы писали:
E>Вот что такое правильные веса в узлах нейро-сети, например?
Веса вычисляются по формуле. Результаты этих вычислений и проверяются на соответствие ей. Правильные веса для теста можно, например, посчитать в Матлабе. Если в алгоритме используется генератор случайных чисел, то для теста ему выдаётся фейковый генератор с известной последовательностью.
Впрочем, я сам ленюсь писать юнит тесты, особенно на исследовтельской стадии, и обхожусь регрессионным тестированием: результаты всей системы или крупных её частей выводятся в текстовом виде и сохраняются в системе контролей версий. Если что-то меняется, то это становится сразу видно, а по дифам обычно можно понять, в чём причина.
Ce n'est que pour vous dire ce que je vous dis.
Re[16]: Как важно проверять в программах ошибки до конца
Здравствуйте, Don Reba, Вы писали:
DR>Веса вычисляются по формуле. Результаты этих вычислений и проверяются на соответствие ей. Правильные веса для теста можно, например, посчитать в Матлабе. Если в алгоритме используется генератор случайных чисел, то для теста ему выдаётся фейковый генератор с известной последовательностью.
Веса классификатора обычно определяются в результате сложного итерационного процесса, называемого обучением.
Формально можно сказать, что в результате обучения мы стремимся подобрать такие коэффициенты, что бы классификатор максимально хорошо классифицировал обучающую выборку. При этом обычно подобрать оптимальный набор коэффициентов не умеют, и подбирают какой-то субоптимальный...
Чего проверят бум?
DR>Впрочем, я сам ленюсь писать юнит тесты, особенно на исследовтельской стадии, и обхожусь регрессионным тестированием: результаты всей системы или крупных её частей выводятся в текстовом виде и сохраняются в системе контролей версий. Если что-то меняется, то это становится сразу видно, а по дифам обычно можно понять, в чём причина.
Во-о-о-от, и все, кто АI занят и известны мне делают так же
Только я боюсь, что дело тут не в том, что "ленбсь", а в том, что юнит-тесты тут фиг напишешь. Правильное поведение системы правда не известно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
N>>Тест не провалится. Потому что тест рассчитан на функцию, которая считает 1) точно, 2) для натурального аргумента, 3) в пределах стандартного int. М>стоп. что такое "старндартный int"? стандарт как раз ничего об этом не говорит.
Стандартный де факто, извините. А это даже для значительной части embedded — 32 бита.
М> вы пишите функцию факториала, а кто-то другой ее компилирует для своей платформы. а если вы тестируете ее исключительно в рамках вашего проекта, то при переходе с 32 на 64 бита -- тест переписывать, т.к. функция работает правильно, а тест проваливается.
Почти так. Переписывать и тест, и функцию. Тест кроме самой функции описывает граничные условия ТЗ (32 бита в int) и проваливается за счёт изменения условий, а уже по факту провала теста обнаруживается, что тут надо переписывать функцию.
N>>Для другой постановки задачи будет другое ТЗ и под него изменятся как реализация, так и тест. М>даже в рамках этой школьной задачи: ТЗ говорит 'int', стандарт говорит, что int это не обязательно 32 бита и зависит от. в реальной жизни там будет не int, а bignum (из сторонней библиотеки) или плавучка.
Да, и так может быть. Удобнее всего было показывать на int'е, но метод проверки сильно зависит от ограничений ТЗ, вызванных особенностями реализации. Если потребуется делать выход в bignum, то не будет ограничения аргумента максимумом в 13, но будет какая-то другая проверка.
М>тогда возникает вопрос -- что тестирует этот тест? функция же работает на любой платформе. забота о переполнении, очевидно, ложиться на вызывающий код, т.к. в самой функции проверок нет.
Почему это? Нормально как раз иметь проверку в функции, если она вообще нужна. Потому что она непосредственно выполняет эти операции и может их проверить. А вызывающая уже оказывается в ситуации, когда она должна проверять по косвенным данным и ненадёжно.
М>это намек на то, что "в лоб" задача тестирования не решается и нужно начинать с провеки какой у нас int.
Не надо с неё начинать. Надо ею заканчивать. Если почему-то функция предполагает возврат int, да, можно сделать проверку при компиляции — если int 32-битный, заглянуть в этот массив, иначе крутиться в цикле умножений (а массив применить для первых значений, насколько возможно). Но если мы знаем, что для всех значимых платформ там 32 бита — можно заложиться на это, обязательно обложив защитой (или в тесте, или при компиляции).
N>>Компилятор и опции тут ни при чём. А затачиваться на 32-битный int сейчас так же нормально, как на реализацию плавучки по IEEE754 или на unix only код. М>это ненормально. потому что при портировании кода на архитектуру с другим размером int'а очень нужны юнит тесты, т.к. при портировании лезут косяки. если же косяки лезут из тестов -- на фига нам такие тесты?
Именно затем, чтобы тесты показали, что предусловие характеристик среды, которое не проверяется в самой функции (потому что не надо его проверять каждый раз) перестало выполняться.
N>>И как это, по-твоему, вычислительная математика ухитряется чего-то достигать, если там всё такое сложное? М>методики тестирования давно разработаны. только сложность тестирования факториала, вычисляемого по функции стирилинга, на порядок сложнее самой этой функции, которая укладывается в одну строку на 80 символов. "порядок" в этом случае -- 10 строк теста. боюсь, что в 10 строк мы не уложимся. в 100 -- может быть. в 1,000 -- однозначно.
Сложность тестирования гамма-функции или стирлинга — проверить несколько ключевых значений. Это то, что реально нужно делать, если мы предполагаем, что среда безошибочна (нет, например, ошибок в процессоре). Какие именно значения — я описывал в предыдущем примере. К ним можно добавить, например, значение ближайшее к зоне превращения результата в INF (чтобы контролировать качество промежуточных расчётом), к денормализованным; но их не так много.
М>вопрос к вам: согласны ли вы, что для факториала, вычисляемого по формуле стирлинга (а это гнутая библиотечная реализация), юнит тест можно заменить интеграционным тестом более высокого уровня. ибо, если у нас косячный факториал, то это это аукнется в использующем его модуле.
Не согласен, пока не знаю, насколько ошибка конкретно факториала влияет на результаты того модуля. Может оказаться, что её влияние порядка 1e-10, в таком случае это близко к погрешности сложной цепочки вычислений.
И поэтому, если у верхнего модуля результаты нестабильно неустойчивы, я в первую очередь обложу проверками все используемые там функции, чтобы быть уверенным, что проблема растёт из самого модуля, а не из библиотек.
М>аналогично, нужно ли тестировать #define MAX(a,b)
Моя позиция отличается от религиозных апологетов TDD тем, что я не считаю, что юнит-тестами надо обкладывать всё и всегда. Действительно, случаи типа MAX(a,b) через сравнение — можно, конечно, обложить парой тестов на простейшие случаи, но сильно стараться тут обычно незачем.
М>написать MAX -- дело секунд пяти. протестировать его -- сложная инженерная задача, требующая глубоких знаний си.
Если тестирующий видит код макроса и заодно заложил пару бомбочек типа i++ для тех, кто будет совсем бездумно менять код — то проблем не будет. И вообще, есть ещё review глазами, и часто до коммита (мы сейчас делаем так в PO), и если пионэр перепишет MAX() с побочными эффектами, то это заметят. Тесты не заменяют code review, но успешно дополняют его.
М>>>да, и еще. совсем забыл. время вычислений -- вполне себе метрика. нормальный тест должен проверять -- не впадает ли функция в нирвану глубокой задумчивости минут на полчаса. N>>С нормальной инфраструктурой подготовки и функционирования тестового окружения — никаких принципиальных проблем. М>вы же сами признали, что проблемы есть. функция факториала работает _везде_ (та, которая на интах). хоть на микроконтроллерах, хоть на суперкомпьютерах с необычной архитектурой. при портировании программы, написанной на ANSI C89, на другую платформу, в идеале достаточно перекомпиляции. а по вашему выходит, что она хоть и работает, но тут же валится на всех тестах, и тесты приходится переписывать или... выбрасывать. в этом и есть _принципиальная_ проблема.
Тест не надо тут "переписывать". Его надо изучить и модифицировать. Но я не вижу ничего принципиального в проблеме. Сама по себе ситуация смены платформы — это очень серьёзный случай. Надо быть готовым к тому, что что-то отвалится, где-то не хватит кода (например, если что-то можно было сделать только на ассемблере), и так далее.
И, заметь, тут пошла речь о другом размере int, но в квотинге тема зависа функции. Именно этот завис надо решать стандартной опцией тестовой инфраструктуры.
N>> Количество ошибок в самом тесте минимально. М>с учетом того, что программа меньше теста и проще -- ошибок в ней еще меньше.
Это сильно зависит от. Например, та же сортировка — кода будет в разы больше, чем в тесте типа "вот 20 значений на входе, а вот же они 20 на выходе вручную проверенные, сравнить побайтово". И даже с 200+ тестовыми наборами данных логически тест в разы проще.
N>> Зачем на понт берёшь, начальник? Нам и так несладко. М>вам-то? вам хорошо. у вас есть си и плюсы. они генерируют машинный код, который можно проверить на вашей стороне. а вот веб-дизайнерам тестировать веб-приложения реально несладко.
Не знаю, к кому ты сейчас обращался, но у меня основная работа — на Erlang и Python.
М>в скриптовых языках, впрочем, тоже. вот я тут столкнулся, что под питоном мой скрипт работает от 2.4 до 2.7 версий. под pypy возникает течь хэндлов и что за ночь работы скрипта их утекает много тысяч. списался с разработчиками. мне объяснили, что это фича и что сборка мусора у них вообще по другому работает.
gc.collect() не помогает? Запустить в фоновом треде с интервалом минут в 10...
М>вот мне интересно -- как это тестировать? на юнит тесте во-первых очень сложно достучаться до счетчиков оси, считающих хэндлы. во-вторых, сложно разобраться сколько этих хэндлов должно быть. это же питон, блин. он сам знает когда их закрывать. и самое печальное -- юнит тест проходит на ура. вызываем мою функцию много-много раз в цикле и по завершению цикла, pypy видит, что программа подходит к концу и чистит все ресурсы. а потому дебит сходится с кредитом. а в реальной ситуации (да еще когда код вызывается из многих потоков), pypy считает, что чистить ресурсы еще рано.
Оценить пределы роста и сделать поправку на них. Вообще да, память это тема для отдельного обсуждения. См. свежий пример
.
М>вообще-то это даже в факе у них написано (что у них такая мегафича), но юнит тест проходит, а интеграционный тест проваливается.
Так и должно быть, если есть влияние чего-то, что лежит за пределами тестируемого.
М>короче, я тут пытаюсь говорить о том, что написание юнит тестов должно быть вдумчивым. прежде чем писать тест нужно взвесить все за и против. наличие юнит-тестов само по себе -- это ни разу не показатель. а бравировать тем, что мы пишем юнит тесты -- вообще смешно. написать тест может и обезьяна. а вот написать корректный и действительно полезный юнит-тест -- это все-таки высший пилотаж.
Полностью согласен.
М>тесты -- нужны. но тестов много. юнит-тесты это как вилка. кушать ей борщ -- теоритически возможно (выловить капусту и мясо, а жидкость высосать, приложившись к тарелке губами), но практически на этот случай есть ложка. ложки есть даже у китайцев, которые едят палочками.
М>короче, мне непонятно, почему если тест, то обязательно юнит.
На том, что тест обязательно юнит-, настаивал (возможно) landerhigh, и то — он не говорил "только", он настаивал на их обязательном присутствии на всём коде. Это не моя позиция. Я считаю, что доступные тестовые ресурсы должны быть распределены по всем уровням, и нарисовать функционально-интеграционный важнее, чем юнит-тесты, хотя в сумме юнит-тестов должно быть больше. И я согласен, что есть куча настолько тривиальных случаев, что юнит-тесты на них рисовать просто незачем.
Но когда говорим о том, что есть проблема (а она по факту есть всегда, программ без багов не бывает) — то отловить её на нижнем уровне всегда легче, чем на верхнем, если она вообще может быть выражена в терминах ошибки конкретной функции или модуля. Поэтому написание тестов — это как оборона на войне. Твоя рота накопала и оборудовала 4 полосы обороны? Замечательно, на свои 12 рабочих часов в день копайте пятый, шестой и так далее. Именно поэтому речь про долю ресурсов (в первую очередь времени) на тестирование: например, постановлено отводить 20% — значит, эти 20% идут на усиление тестов того, что уже написано. Есть юнит-тест на функцию на 5 случаев? Отлично, нарисовать ещё 5. Не было теста, потому что тривиальщина типа MAX()? Нарисовать пару тривиальных случаев. Не было функционального в варианте, когда компонент D умер посредине обычной работы? Сесть и нарисовать. Нет инверсий? Придумать парочку. Ну и так далее.
The God is real, unless declared integer.
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, мыщъх, Вы писали:
N>>Здравствуйте, мыщъх, Вы писали:
N>>Тест не провалится. Потому что тест рассчитан на функцию, которая считает 1) точно, 2) для натурального аргумента, 3) в пределах стандартного int. М>стоп. что такое "старндартный int"? стандарт как раз ничего об этом не говорит. вы пишите функцию факториала, а кто-то другой ее компилирует для своей платформы. а если вы тестируете ее исключительно в рамках вашего проекта, то при переходе с 32 на 64 бита -- тест переписывать, т.к. функция работает правильно, а тест проваливается.
мыщъх, задача теста и состоит в том, чтобы провалитсья, если вдруг что-то пошло не так. Само наличие тестов облегчает переход на другую платформу в стопиццот раз. И даже если, как ты тут написал, тест падает потому, что он сам был кривой и не рассчитан на другую разрядность (хотя это нужно постаратсья такое отмочить), то это прекрасный индикатор того, что что-то протестировано неправильно/недостаточно.
М>это намек на то, что "в лоб" задача тестирования не решается и нужно начинать с провеки какой у нас int.
Даже самую блестящую идею можно довести до идиотизма.
N>>Компилятор и опции тут ни при чём. А затачиваться на 32-битный int сейчас так же нормально, как на реализацию плавучки по IEEE754 или на unix only код. М>это ненормально. потому что при портировании кода на архитектуру с другим размером int'а очень нужны юнит тесты, т.к. при портировании лезут косяки. если же косяки лезут из тестов -- на фига нам такие тесты?
Если косяки лезут из тестов, это означает, что программист, написавший код и тест, не предполагал такого использования для тестируемого кода. Это повод для перепроверки. И, честно говоря, гораздо легче перепроверять код под тестами, чем потом после сотен человеко-часов в отладчике выяснять, где кто и как напутал с endianess, например.
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, landerhigh, Вы писали:
L>>Сравниваешь теплое с мягким. Тесты выполяются автоматически во время каждого билда, и отладочная печать и логи по сравнению с ними находятся в одином ряду с каменным топором по сравнению с современным станком с ЧПУ.
N>А вот тут таки ерундите. Потому что слишком завязываетесь на юнит-тесты, в то время как реальная ситуация может требовать и другие виды функциональных тестов, включая запуск целых компонентов и подсистем в обстановке, эмулирующей реальную. Такие комплексные функциональные тесты тоже могут (и должны) запускаться автоматически, и для анализа их проблем логи и отладочная печать жизненно необходимы.
Я нигде не отрицал необходимость тестирования на всех уровнях. Я лишь обращаю внимание на то, что чаще всего встречается подход "нам тесты писать не надо, нам копать надо, да и вдруг потом размер инта поменяется, что нам все тесты переписывать, что ли, а тестируют пусть потом тестеры, им за это деньги платят". Вот такой вот подход как правило приводит к массивным epic fail. Что меня удивляет, так это то, что мыши продолжают жрать кактус.
L>>Цитату можно, где я соглашался? L>>Эти 3000 тестов будут состоять из трех-четырех строчек каждый; трудоемкость их написания на фоне затрат на разработку основного кода незаметна, а объем — вообще странная метрика. Более того, факт написания тестов оказывает положительный эффект на разработку собственно кода, поскольку тестируемый код должен удовлетворять критериям тестируемости, которые магическим образом совпадают с обобщенными критериями "хорошести" и "поддерживаемости" кода. Выполнение этих тестов занимает несколько секунд. L>>Трудоемкость такого подхода совершенно ничтожна по сравнению с затратами, которые потребовались бы на орагнизацию аналогичного по покрытию набора функциональных black-box тестов.
N>Их сравнивать в принципе нельзя. В реальности нужны и те, и другие.
Совершенно верно. Но гораздо легче протестировать корректность работы мифического вычислителя факториала, обращаясь к нему напрямую, нежели пытаясь угадать, какие именно данные нужно подсунуть системе, чтобы протестировать то или иное граничное условие в нем.
М>>>например, если это пульт управления микроволновой печи -- модель _доказывает_, что нельзя войти в меню из которого потом не выйти. именно, что _доказывает_, причем верификация осуществляется автоматически. L>>А вот тут я, как и обещал, порву тебя на лоскуты. Пульт управления микроволновки — это типичный пример state machine. То, что в ней нет тупиков, доказывается в первую очередь диаграммой состояний вашей машины и таблицей переходов. Верифицируется ручками, глазками, и девайсом /dev/brain. Как и все подобные конечные автоматы.
N>А у мыщъха оно верифицируется специальной тулзой, которая доказывает наличие пути из любой точки. И эта тулза точно так же может запускаться автоматически и не зависеть от того, что тот, кто в ковырнадцать тысяч ёкарнадцатый раз пролистал FSM на тему "ну чего они тут ещё натворили", случайно нажал PgDn дважды и пропустил какое-то важное изменение.
Вот это, кстати, и есть тот момент в реализации КА на ЯВУ, за который я рву народ на лоскуты. Но это оффтопик, если интересно, можем начать новую тему.
L>> А вот после реализации можно и нужно написать функциональный тест, который в том числе проверит, что из каждого меню можно выйти в $HOME.
N>И сколько ты будешь писать этот тест?
Я — минут пять, наверное. За Криса не скажу.
L>>>>Дорогой, ты только что привел примеры двух индустрий, L>>>>где юнит-тестирование проводится практически везде. М>>>и обе индустрии вбухивают в тестирование мегабабло. потому что цена ошибки дороже. L>>Знаем мы, куда они мегабабло вбухивают. На бонусы непричастным и сетрификацию некомпетентными.
N>Оффтопик и намёк на слив.
Да ладно?
L>>Нет никаких особых расходов на разработку этих тестов. Вообще, когда спрашивают о расходах на разработку тестов, это является признаком полного непонимания подхода TDD и использования юнит-тестов в разработке. Этот процесс не разделим на составные части.
N>Разделим, разделим. Как только ты начинаешь осознавать, что тех же юнит-тестов даже для простейшей функциональности можно нарисовать разумное количество, а можно — почти бесконечность, то начинается понимание, что тестирование тоже способно занять 101% времени и прочих ресурсов и его необходимо разумно ограничивать.
Я не разделяю собственно кодинг и юнит-тестирование. Меня тут фиг ограничишь
L>>Как только разработчик становится адептом церкви TDD на своем опыте узнает преимущество юнит-тестирования, для него юнит-тесты перестают существовать как отдельная сущность.
N>Я давно знал, что TDD — это не методика, а религия.
Ага. В нашей религии даже принято приносить жертвы. Например, кукла демона "овертайм перед релизом" приносится в жертву идолу "работаем с десяти до пяти с перерывом на обед".
L>> Для нас процесс разработки есть процесс написания собственно кода и кода, его тестирующего. Они неотделимы друг от друга, как неотделимы и наши собственные оценки затрат и как результат, бюджет. Кроме того, наши оценки временных затрат зачастую являются гораздо более точными, так как, прежде чем приступить к estimations, мы должны не только ответить на вопрос "а что мы будем писать", но и "а как мы это будем автоматически тестировать".
N>Полностью согласен (только надо учесть ещё и ручное тестирование, хотя бы на верхних уровнях, которое всё равно обязательно).
Вот это мы как раз оставляем тестерам. Если мы еще и это сами автоматизируем, то нам темную устроят.
CL>оказалось, после 2-х недель выяснения причин вот этого самого "упало" (код упавшего модуля я вообще впервые увидел), что виноват сторонний платный компонент, и ещё неделя ушла на придумывание теста, на котором оно гарантированно падает.
Да, совершенно верно, раз сторониий компонент упал, то и писать юнит-тесты не надо
Юнит-тесты по определению не предназначены для выявления багов в сторонних компонентах. Так получается, что во многих случаях их удобно использовать для верификации того, что этот самый сторонний компонент делает то, что обещал. Но не более того.
Но! наличие приличного покрытия кода юнит-тестами может помочь тебе сузить круг поиска. Так, после анализа дампа у тебя под подозрение попали компоненты A, B и C, но быстрый просмотр тестов показал, что подозрительные тест-кейсы в них покрыты. Это исключает их из списка кандидатов. Более того, иногда можно даже написать тест, доказывающий, что проблема не в вашем коде, но это уже продвинутый пилотаж.
CL>но "упало" — половина беды, а вот если повисло...
E>>>Ну торговля на бирже, например, или распознавание речи...
E>Ты просил пример системы, а не класса.
Мы тут говорим о юнит-тестах. Систему тестируют функциональными тестами.
Но, даже если не существует однозначного индикатора правильного поведения системы, сисема всегда имеет ожидаемую реакцию. Отсюда можно выделить критерий приемлимости. Например, генератор случайных чисел в лоб тестировать нельзя, но можно набрать выборку из 100500 значений и посчитать распределение.
Здравствуйте, landerhigh, Вы писали:
L>Мы тут говорим о юнит-тестах. Систему тестируют функциональными тестами.
Я привёл пример класса, точное поведение которого неизвестно. Скажем мы пишем самообучающийся спам-фильтр.
И там у нас есть обучалка классификатора, классификатор и отборщик признаков. Ну и как их всех троих юнит-тестировать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Как важно проверять в программах ошибки до конца
Здравствуйте, landerhigh, Вы писали:
L>Нет никаких затрат на поддержание тестов. Если они есть, вы что-то делаете неправильно. Это мое профессиональное мнение, основанное на десятках коммерческих проектов.
Ну вот например, функция изначально возвращала один набор результатов, потом требования поменялись, набор результатов был слегка изменен. Тест падает — его приходиться перезаточить под новые требования. Как вы эти ситуации обходите?
L>Никогда не путай QA и юнит-тестирование. Их задачи разные. Использовать QA для отлова того, что должно было быть протестировано юнит-тестом равносильно стрельбе из пушки по комарам.
Не понял практического применения этого высказывания. Никто и не путает.
F>>Это наблюдения из практики как она есть — никаких теорий.
L>Моя наблюдения из практики почему-то своершенно другие.
Возможно. Я, к сожалению, не разу не учасвтвовал в ваших проектах. Мне бы действительно интересно посмотреть на успешное применения сего в действии, может действительно можно было бы научиться чему новому. К сожалению, поверить наслово совсем не могу, ибо манера выражения у тебя типа "я крутой разработчик", а остольные просто не догоняют. Такая манера вызывает некоторое недоверие, даже если ты действительно что-то умеешь делать лучше, чем другие.
L>Вот моги главные замеченные отличие проектов, написанных в стиле "тесты писать некогда, нужно копать" от тех, где тесты, и много, были написаны:
L>2. Ошибки, найденные во время QA на проектах, покрытых юнит-тестами, разительно отличаются от ошибок, найденных на классических проектах. Обычно они лежат в плоскости "а мы считаем, что здесь спеки требуют другого поведения" и "поведение соответствует спекам, но заказчик понял, что ошибся в спеках и поэтому поведение нужно изменить", в то время как багрепорты от QA на
классических проектах пестрят "упало", "не работает вообще", "сожрало всю память и опять упало" и прочими WTF.
Не уверен, что тут действительно достоинство. Многие вещи из "не работают вообще" действительно быстрее и дешевле отловить QA, чем девелоперу девелопить юнит тесты. Это если взаимодейсвие с QA достадочно эффективно и динамично. Конечно, выглядить "круче", что постовляемый функционал в QA чище, но не дешевле и быстрее. Многие из этой категории протестировать неполучается из-за недостатка информации. Например, есть поиск по моделям, среди номеров моделей есть модели содержащие символ "*". На них поиск работает некорректно. Такие модели встречаются очень редко, поэтому девелопер о них не знал, но QA знает. Конечно, можно девелоперу провести исследования и выявить все возможные комбинации, несмотря на то, что моделей около 6 миллионов (и могут добавляться), но зачем ему повторять работу, которая уже проделанна QA? Да, код будет изначально без ошибки, но время и затраты на его создание будут больше.
А вот мне интересно, как ловить в юнит тестах такие вещи как "сожрало всю память". Была недавно ошибка, где соединения с базой данных не освобождались. Сам юнит соеденение явно не освобождает, все это происходит внутри сторонних библиотек и нескольких custom конфигураций, так что в самом юните все правильно (ошибка была в конфигурации управления в отдельном файле). По идее, нужно проверить состояние connection pool на предмет наличия увеличения количества активных соеденений помеченных как "используемые", но он запрятан глубоко в недрах application server и таких возможностей не предоставляет.
L>3. Проекты, покрытые юнит-тестами, намного более гибкие в смысле дальшейшего развития и обеспечивают возможность легкого рефакторинга.
Не очень понял как это связанно с юнит-тестами. Если проект хорошо организован, так он хорошо организован. Как тесты добовляют гибкости?
L>4. Из юнит-тестов можно вычленять автоматические функциональные тесты, облегчая работу QA
Это несколько зависит от организации разработки. Во многих проектах сейчас методология совместной и одновременно работы QA и разработки. Так что на момент, когда разработка завершенна, QA готов тестировать.
Я тут как бы не с точки зрения поспорить — у меня совершенно практический интерес. Вряд ли, конечно, я что-то новое смогу почерпнуть, ибо слова не практика, но может какие-то идеи.
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, Fantasist, Вы писали:
F> Многие из этой категории протестировать неполучается из-за недостатка информации. Например, есть поиск по моделям, среди номеров моделей есть модели содержащие символ "*". На них поиск работает некорректно. Такие модели встречаются очень редко, поэтому девелопер о них не знал, но QA знает. Конечно, можно девелоперу провести исследования и выявить все возможные комбинации, несмотря на то, что моделей около 6 миллионов (и могут добавляться), но зачем ему повторять работу, которая уже проделанна QA? Да, код будет изначально без ошибки, но время и затраты на его создание будут больше.
На самом деле тут интересный вопрос, который обычно решается следующим:
1. Если возникают такие ситуации, то ТЗ на функцию должно быть явно доработано с указанием, что '*' возможно, что поиск на них должен работать — и как следствие, должен быть написан на это тест.
2. Надо вспомнить и не забывать применять, что QA это не только тестеры, но тут хороший пример того, что QA должен принимать участие и в выработке ТЗ.
F> А вот мне интересно, как ловить в юнит тестах такие вещи как "сожрало всю память".
Запускать тест в резко ограниченном по памяти окружении. Не знаю, как в Windows, но в Unix это тривиально (ulimit в шелле).
L>>3. Проекты, покрытые юнит-тестами, намного более гибкие в смысле дальшейшего развития и обеспечивают возможность легкого рефакторинга. F> Не очень понял как это связанно с юнит-тестами. Если проект хорошо организован, так он хорошо организован. Как тесты добовляют гибкости?
У хорошо тестируемого проекта лучше выделены отдельные компоненты и прорисованы логические связи между ними, в отличие от цельной каши, которая обычно поддаётся только ручному тестированию.
L>>4. Из юнит-тестов можно вычленять автоматические функциональные тесты, облегчая работу QA F> Это несколько зависит от организации разработки. Во многих проектах сейчас методология совместной и одновременно работы QA и разработки. Так что на момент, когда разработка завершенна, QA готов тестировать.
А тут одно другому не мешает.
The God is real, unless declared integer.
Re[11]: Как важно проверять в программах ошибки до конца
Здравствуйте, Fantasist, Вы писали:
F>Здравствуйте, landerhigh, Вы писали:
L>>Нет никаких затрат на поддержание тестов. Если они есть, вы что-то делаете неправильно. Это мое профессиональное мнение, основанное на десятках коммерческих проектов.
F> Ну вот например, функция изначально возвращала один набор результатов, потом требования поменялись, набор результатов был слегка изменен. Тест падает — его приходиться перезаточить под новые требования. Как вы эти ситуации обходите?
Что значит "требования поменялись?" API модуля изменилось? Так тут тест не упадет, а просто не скомпилируется, вместе с остальной системой. Или изменилась логика и данные, которые раньше считались валидными, быть таковыми перестали и тест "вдруг" стал валиться?
Если второе, то в этом и предназначение тестов — валиться в случае breaking changes. Считайте свой код набором отдельных сущностей (юнитов) с определенным контрактом на поведение. Юниты, использующие друг друга, на этот контракт рассчитывают. Ваши тесты должны проверять, что юниты соблюдают договоренности. Если тест свалился — это, как говорится, code red — кто-то нарушает заключенные ранее договоренности, и юниты, зависящие от данного конкретного измененного юнита вполне могут пострадать. Автор этих изменений должен удостовериться, что после его изменений все тесты остаются зелеными.
Другое дело, что в нашем случае это никогда проблемой не является ввиду изначальной ориентировки кода на тестирование, адаптация тестов под измененные требования проходит почти моментально, в течение считанных минут. Следует отметить, что мы не на 100% следуем классической парадигме тестирования, когда тест пишется только для конкретного юнита, а все зависимости заменяются моками, у нас бывает, что один простецкий тест на три строчки на поверку прогоняет половину кода системы. Как результат — изменение, ломающее тест какого-нибудь модуля в самом начале цепочки зависимостей, иногда приводит к лавине красных тестов. Мы об этом заранее знаем и к этому готовы, более того, подобные вещи позволяют представить значение данного конкретного изменения и, как следствие, переработать архитектуру, если нужно.
L>>Никогда не путай QA и юнит-тестирование. Их задачи разные. Использовать QA для отлова того, что должно было быть протестировано юнит-тестом равносильно стрельбе из пушки по комарам. F> Не понял практического применения этого высказывания. Никто и не путает.
В 98% случаев путают таки.
F>>>Это наблюдения из практики как она есть — никаких теорий.
L>>Моя наблюдения из практики почему-то своершенно другие.
F> Возможно. Я, к сожалению, не разу не учасвтвовал в ваших проектах. Мне бы действительно интересно посмотреть на успешное применения сего в действии, может действительно можно было бы научиться чему новому. К сожалению, поверить наслово совсем не могу, ибо манера выражения у тебя типа "я крутой разработчик", а остольные просто не догоняют. Такая манера вызывает некоторое недоверие, даже если ты действительно что-то умеешь делать лучше, чем другие.
так большинство программистов, не искользующих юнит-тесты, с которыми приходилось общаться, цепляются за какой-нибудь унылый аргумент вроде "это ж поддерживать надо", "некогда ерундой заниматься", "а вдруг прилетит волшебник в голубом вертолете и бесплатно покажет кино" и так далее. На любой мой аргумент из моей практики находится своя сферическая мельница в вакууме, а со сферическими мельницами в вакууме я не борец.
L>>Вот моги главные замеченные отличие проектов, написанных в стиле "тесты писать некогда, нужно копать" от тех, где тесты, и много, были написаны:
L>>2. Ошибки, найденные во время QA на проектах, покрытых юнит-тестами, разительно отличаются от ошибок, найденных на классических проектах. Обычно они лежат в плоскости "а мы считаем, что здесь спеки требуют другого поведения" и "поведение соответствует спекам, но заказчик понял, что ошибся в спеках и поэтому поведение нужно изменить", в то время как багрепорты от QA на F>классических проектах пестрят "упало", "не работает вообще", "сожрало всю память и опять упало" и прочими WTF.
F> Не уверен, что тут действительно достоинство.
Лично я привык считать, что продукт, передаваемый в QA, должен быть в заведомо работоспособном состоянии.
F> Многие вещи из "не работают вообще" действительно быстрее и дешевле отловить QA, чем девелоперу девелопить юнит тесты.
Гораздо лучше, если "не работает вообще" вообще не возникает. Опять же, не сравнивай крокодилов с апельсинами, QA и юнит тестирование совершенно ортогональны.
F> Это если взаимодейсвие с QA достадочно эффективно и динамично. Конечно, выглядить "круче", что постовляемый функционал в QA чище, но не дешевле и быстрее.
Прогнать юнит-тест — несколько секунд. Сколько часов у QA уйдет на запуск ручного теста, и ввод инофрмации о баге в баг-трекер? то-то и оно.
F> Многие из этой категории протестировать неполучается из-за недостатка информации. Например, есть поиск по моделям, среди номеров моделей есть модели содержащие символ "*". На них поиск работает некорректно. Такие модели встречаются очень редко, поэтому девелопер о них не знал, но QA знает.
Извини, но это плохой, негодный девелопер В моем уютном мирке сферический девелопер в вакууме напишет тест, проверяющий работу поиска со всех сторон, включая "подозрительные" символы. То есть — именно подобные баги мы давим еще в зародыше.
F> Конечно, можно девелоперу провести исследования и выявить все возможные комбинации, несмотря на то, что моделей около 6 миллионов (и могут добавляться), но зачем ему повторять работу, которая уже проделанна QA? Да, код будет изначально без ошибки, но время и затраты на его создание будут больше.
А я как раз об этом уже писал. Громадный плюс юнит-тестов в том, что ты можешь тестировать на любом уровне. Вместо тестирования поиска по ковырнадцати миллионам "моделей" программист может и должен написать тест, проверяющий допустимость тех или иных символов. Вопрос про звездочку возникнет при этом закономерно.
F> А вот мне интересно, как ловить в юнит тестах такие вещи как "сожрало всю память".
Сожрало всю память — это либо логическая ошибка (создание квадриллиона ненужных сущностей), которые юнит-тесты давят в зародыше, либо быстрый memory leak. Наличие последних часто детектится включением _CrtDumpMemoryLeaks в main() юнит-теста. Очень удобно — написал код и тест, запустил, а оно тебе и говорит "тут, братец, память где-то течет". Не всегда, конечно, спасает, но не заметить бревно в глазу не даст.
F> Была недавно ошибка, где соединения с базой данных не освобождались. Сам юнит соеденение явно не освобождает, все это происходит внутри сторонних библиотек и нескольких custom конфигураций, так что в самом юните все правильно (ошибка была в конфигурации управления в отдельном файле). По идее, нужно проверить состояние connection pool на предмет наличия увеличения количества активных соеденений помеченных как "используемые", но он запрятан глубоко в недрах application server и таких возможностей не предоставляет.
Всегда можно найти что-то что покрыть юнит-тестом невозможно. Например, чужой application server или сервер БД.
L>>3. Проекты, покрытые юнит-тестами, намного более гибкие в смысле дальшейшего развития и обеспечивают возможность легкого рефакторинга.
F> Не очень понял как это связанно с юнит-тестами. Если проект хорошо организован, так он хорошо организован. Как тесты добовляют гибкости?
Тесты заставляют структурировать код таким образом, чтобы он был тестируем. Это значит — минимум связей, хорошая изолированность отдельных юнитов и соответствующая архитектура.
L>>4. Из юнит-тестов можно вычленять автоматические функциональные тесты, облегчая работу QA
F> Это несколько зависит от организации разработки. Во многих проектах сейчас методология совместной и одновременно работы QA и разработки. Так что на момент, когда разработка завершенна, QA готов тестировать.
У нас QA начинает тестировать задолго до окончания разработки — после первого же внутреннего релиза (обычно после первого или второго спринта). У нас были отличные проекты, на которых мы сидели в одной комнате с тестерами — на ранних этапах нам даже не нужно было ничего в баг трекер заводить, если тестеры находили чего.
Здравствуйте, мыщъх, Вы писали:
м> М>>извините, но у вас ноги из попы растут.
м> Q>Ваше мнение озвучено, но отвергнуто как несостоятельное. До свидания.
м> обосновать сможете? ну или давайте письками меряться. если мой код на паскале будет работать сильно медленнее вашего асма -- считайте, что у вас длинеее. и, соответственно, наоборот. код тот же что и у вас (по функционалу), компилятор -- аналогично.
Хацкер крыс, ломающий интеловые камни ( ), закинулся феназепамом и разглядел асм в чисто-паскалевом коде Вытащи уже титан из задницы, или куда ты там его засовываешь, он, похоже, усугубляет действие веществ
m> незнание матчасти, незнание принципов построения осей и компиляторов и прочего фундаментализма не позволяет вам решать задачи на паскале без тормозов.
Твоей коровке постоять бы в сторонке, да помолчать в тряпочку.
Здравствуйте, Erop, Вы писали:
L>>Мы тут говорим о юнит-тестах. Систему тестируют функциональными тестами. E>Я привёл пример класса, точное поведение которого неизвестно. Скажем мы пишем самообучающийся спам-фильтр. E>И там у нас есть обучалка классификатора, классификатор и отборщик признаков. Ну и как их всех троих юнит-тестировать?
Юнит-тесты делаются не на класс, а на отдельный метод. Поведение которого строго определено. Далее, мы можем не знать, во что выльется обучение на конкретных примерах, но мы можем рассчитать, какая комбинация входного состояния и воздействия даст какое выходное состояние, на нескольких примерах, отобранных по характерным признакам, и проверить работу именно по соответствию тому, что мы ожидаем.
The God is real, unless declared integer.
Re[14]: Как важно проверять в программах ошибки до конца
Здравствуйте, netch80, Вы писали:
N>Юнит-тесты делаются не на класс, а на отдельный метод. Поведение которого строго определено. Далее, мы можем не знать, во что выльется обучение на конкретных примерах, но мы можем рассчитать, какая комбинация входного состояния и воздействия даст какое выходное состояние, на нескольких примерах, отобранных по характерным признакам, и проверить работу именно по соответствию тому, что мы ожидаем.
Какой в этом смысл?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[15]: Как важно проверять в программах ошибки до конца
Здравствуйте, Erop, Вы писали:
N>>Юнит-тесты делаются не на класс, а на отдельный метод. Поведение которого строго определено. Далее, мы можем не знать, во что выльется обучение на конкретных примерах, но мы можем рассчитать, какая комбинация входного состояния и воздействия даст какое выходное состояние, на нескольких примерах, отобранных по характерным признакам, и проверить работу именно по соответствию тому, что мы ожидаем. E>Какой в этом смысл?
Такой же как в других тестах — проверить соответствие выполняемого ожидаемому. Что тут непонятно?
The God is real, unless declared integer.
Re[16]: Как важно проверять в программах ошибки до конца
Здравствуйте, netch80, Вы писали:
N>Такой же как в других тестах — проверить соответствие выполняемого ожидаемому. Что тут непонятно?
Дык ожидаемое известно не точно
Вот смотри, пусть наш классификатор -- машина опорных векторов. У этого классификатора есть два этапа жизни.
1) Обучение -- из большой обучающей выборки выбирается какое-то количество векторов, которые в дальнейшем считаются опорными, и для каждого из векторов вычисляется несколько чисел.
2) Классификация -- берём новый вектор, и применяем классификатор -- в ответ он называет класс, и вес. Вес -- это параметр. Который задаёт степень уверенности классификатора в том, что это этот класс.
Первый этап вообще носит стохастический характер часто, так что там с юнит-тестированием всё непросто. Максимум, что вы можете -- проверит работоспособность обучалки, но не качество её работы. А интересует, обычно, именно качество, и скорость.
Второй, казалось бы, детерминирован, и юнит-тест написать можно.
Но если посмотреть на реальные классификаторы, то мы увидим, что там всё заоптимизировано, в частности для хранения тех самых чисел часто используют целые небольшой битности. Так что существенный вклад в результат распознавания начинает вносить шум квантетизации. При этом это легко учитывается при обучении, так как обучение часто итерационный процесс, то нет проблемы обучать сразу с шумом квантетизации.
Но, в результате, мы получаем, что стоит пошевелить классификатор, например сместить его шумы квантетизации, так именитс и "правильный" отклик, даже не эталонных результатах.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском