Здравствуйте, 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>И там у нас есть обучалка классификатора, классификатор и отборщик признаков. Ну и как их всех троих юнит-тестировать?
Юнит-тесты делаются не на класс, а на отдельный метод. Поведение которого строго определено. Далее, мы можем не знать, во что выльется обучение на конкретных примерах, но мы можем рассчитать, какая комбинация входного состояния и воздействия даст какое выходное состояние, на нескольких примерах, отобранных по характерным признакам, и проверить работу именно по соответствию тому, что мы ожидаем.