Сообщение Re[12]: дебагинг vs unit-тесты vs ассерты от 04.05.2016 18:57
Изменено 05.05.2016 3:58 netch80
Здравствуйте, landerhigh, Вы писали:
К>>Дано: написал кривой код, который на редких условиях зримо глючит. Обкладывай его тестами для поиска бага.
L>Эээ, тесты не для поиска багов. А для написания верифицируемого в контролируемых условиях кода. Почувствуйте разницу (с).
Вначале я думал этому мягко возразить, но, подумав, скорее соглашусь. Формулировка слегка коварная, но правильная. (За неё плюс и баллы, как бы я ни относился к остатку письма.)
Верификацию в нашей типичной реальности проводит в основном человек, с небольшой помощью компилятора. В некоторых случаях, как в соседнем треде про ATS, чуть больше чем небольшой, но всё равно его участие основное.
И чтобы эта верификация проходила успешно, человеку надо помочь.
Более того, даже при машинной верификации тестирование всё равно необходимо — чтобы повысить шансы, что условия, включённые в аксиоматику верификатора, действительно истинны.
L>TEST(go_around_zero_v2, testNegativeN)
Вот тут уже начинаются нелады. Основная проблема в том, что ты поддался на откровенную провокацию Кодта. Провокация эта не в INT_MIN или в чём-то подобном; провокация в том, что ты согласился рассматривать именно его постановку задачи в виде этой функции и его разбиение кода этой функции на структурные части. А это тут не нужно. Проверка кода в таком виде или вообще не проверяется тестами, или тесты станут повторять последствия математической верификации кода; но тогда им нужно проверять не выходной скомпилированный результат, а промежуточный отчёт компилятора (gcc, например, на каком-то этапе выдаёт возможные границы значений переменных) или вообще исходный код! Это работа статического анализатора, который должен был сказать "эгегей, если у тебя n>214748364, то у тебя проблемы с UB, а если n<0, то вообще непонятно, чего ты тут хотел добиться". То есть всё равно верификатор.
Итого, лучше всего было просто отказаться рассматривать в таком виде.
L> unsigned int expected = n*10*2+1; // Ну или 100500 от балды, чтобы просто отловить бесконечный цикл
Так не отловишь же — оно может захотеть вообще ничего не делать. Да и в реальности бесконечного цикла не будет при любом из возможных переполнений.
Пока что, если ты пишешь тест, уже зная про потенциальную возможность UB, тебе нет смысла писать тест именно на UB именно потому, что UB непредсказуемо и поэтому заведомо за рамками тестирования.
(Разве что апостериорного статистического, но это совсем другой разговор.)
Вот если бы речь шла про C# и checked context, или аналогичное средство, где переполнение гарантируется, можно было бы его явно проверить только зачем? И без нас есть кому проверить компилятор
К>>А в это время в Виллабаджо уже делают фигак-фигак-продакшен.
L>)
L>Через 3 месяца тестеры пишут баг-репорт "падает". Смотришь в лог, видишь bananas. Пинаешь того, кто вызывал твой код.
Всё-таки в контрактах это уместнее.
L>До приемлимой.
На всякий случай — "приемлемой".
К>>Дано: написал кривой код, который на редких условиях зримо глючит. Обкладывай его тестами для поиска бага.
L>Эээ, тесты не для поиска багов. А для написания верифицируемого в контролируемых условиях кода. Почувствуйте разницу (с).
Вначале я думал этому мягко возразить, но, подумав, скорее соглашусь. Формулировка слегка коварная, но правильная. (За неё плюс и баллы, как бы я ни относился к остатку письма.)
Верификацию в нашей типичной реальности проводит в основном человек, с небольшой помощью компилятора. В некоторых случаях, как в соседнем треде про ATS, чуть больше чем небольшой, но всё равно его участие основное.
И чтобы эта верификация проходила успешно, человеку надо помочь.
Более того, даже при машинной верификации тестирование всё равно необходимо — чтобы повысить шансы, что условия, включённые в аксиоматику верификатора, действительно истинны.
L>TEST(go_around_zero_v2, testNegativeN)
Вот тут уже начинаются нелады. Основная проблема в том, что ты поддался на откровенную провокацию Кодта. Провокация эта не в INT_MIN или в чём-то подобном; провокация в том, что ты согласился рассматривать именно его постановку задачи в виде этой функции и его разбиение кода этой функции на структурные части. А это тут не нужно. Проверка кода в таком виде или вообще не проверяется тестами, или тесты станут повторять последствия математической верификации кода; но тогда им нужно проверять не выходной скомпилированный результат, а промежуточный отчёт компилятора (gcc, например, на каком-то этапе выдаёт возможные границы значений переменных) или вообще исходный код! Это работа статического анализатора, который должен был сказать "эгегей, если у тебя n>214748364, то у тебя проблемы с UB, а если n<0, то вообще непонятно, чего ты тут хотел добиться". То есть всё равно верификатор.
Итого, лучше всего было просто отказаться рассматривать в таком виде.
L> unsigned int expected = n*10*2+1; // Ну или 100500 от балды, чтобы просто отловить бесконечный цикл
Так не отловишь же — оно может захотеть вообще ничего не делать. Да и в реальности бесконечного цикла не будет при любом из возможных переполнений.
Пока что, если ты пишешь тест, уже зная про потенциальную возможность UB, тебе нет смысла писать тест именно на UB именно потому, что UB непредсказуемо и поэтому заведомо за рамками тестирования.
(Разве что апостериорного статистического, но это совсем другой разговор.)
Вот если бы речь шла про C# и checked context, или аналогичное средство, где переполнение гарантируется, можно было бы его явно проверить только зачем? И без нас есть кому проверить компилятор
К>>А в это время в Виллабаджо уже делают фигак-фигак-продакшен.
L>)
L>Через 3 месяца тестеры пишут баг-репорт "падает". Смотришь в лог, видишь bananas. Пинаешь того, кто вызывал твой код.
Всё-таки в контрактах это уместнее.
L>До приемлимой.
На всякий случай — "приемлемой".
Re[12]: дебагинг vs unit-тесты vs ассерты
Здравствуйте, landerhigh, Вы писали:
К>>Дано: написал кривой код, который на редких условиях зримо глючит. Обкладывай его тестами для поиска бага.
L>Эээ, тесты не для поиска багов. А для написания верифицируемого в контролируемых условиях кода. Почувствуйте разницу (с).
Вначале я думал этому мягко возразить, но, подумав, скорее соглашусь. Формулировка слегка коварная, но правильная. (За неё плюс и баллы, как бы я ни относился к остатку письма.)
Верификацию в нашей типичной реальности проводит в основном человек, с небольшой помощью компилятора. В некоторых случаях, как в соседнем треде про ATS, чуть больше чем небольшой, но всё равно участие человека основное.
И чтобы эта верификация проходила успешно, человеку надо помочь.
Более того, даже при машинной верификации тестирование всё равно необходимо — чтобы повысить шансы, что условия, включённые в аксиоматику верификатора, действительно истинны.
L>TEST(go_around_zero_v2, testNegativeN)
Вот тут уже начинаются нелады. Основная проблема в том, что ты поддался на откровенную провокацию Кодта. Провокация эта не в INT_MIN или в чём-то подобном; провокация в том, что ты согласился рассматривать именно его постановку задачи в виде этой функции и его разбиение кода этой функции на структурные части. А это тут не нужно. Проверка кода в таком виде или вообще не проверяется тестами, или тесты станут повторять последствия математической верификации кода; но тогда им нужно проверять не выходной скомпилированный результат, а промежуточный отчёт компилятора (gcc, например, на каком-то этапе выдаёт возможные границы значений переменных) или вообще исходный код! Это работа статического анализатора, который должен был сказать "эгегей, если у тебя n>214748364, то у тебя проблемы с UB, а если n<0, то вообще непонятно, чего ты тут хотел добиться". То есть всё равно верификатор.
Итого, лучше всего было просто отказаться рассматривать в таком виде.
L> unsigned int expected = n*10*2+1; // Ну или 100500 от балды, чтобы просто отловить бесконечный цикл
Так не отловишь же — оно может захотеть вообще ничего не делать. Да и в реальности бесконечного цикла не будет при любом из возможных переполнений.
Пока что, если ты пишешь тест, уже зная про потенциальную возможность UB, тебе нет смысла писать тест именно на UB именно потому, что UB непредсказуемо и поэтому заведомо за рамками тестирования.
(Разве что апостериорного статистического, но это совсем другой разговор.)
Вот если бы речь шла про C# и checked context, или аналогичное средство, где переполнение гарантируется, можно было бы его явно проверить только зачем? И без нас есть кому проверить компилятор
К>>А в это время в Виллабаджо уже делают фигак-фигак-продакшен.
L>)
L>Через 3 месяца тестеры пишут баг-репорт "падает". Смотришь в лог, видишь bananas. Пинаешь того, кто вызывал твой код.
Всё-таки в контрактах это уместнее.
L>До приемлимой.
На всякий случай — "приемлемой".
К>>Дано: написал кривой код, который на редких условиях зримо глючит. Обкладывай его тестами для поиска бага.
L>Эээ, тесты не для поиска багов. А для написания верифицируемого в контролируемых условиях кода. Почувствуйте разницу (с).
Вначале я думал этому мягко возразить, но, подумав, скорее соглашусь. Формулировка слегка коварная, но правильная. (За неё плюс и баллы, как бы я ни относился к остатку письма.)
Верификацию в нашей типичной реальности проводит в основном человек, с небольшой помощью компилятора. В некоторых случаях, как в соседнем треде про ATS, чуть больше чем небольшой, но всё равно участие человека основное.
И чтобы эта верификация проходила успешно, человеку надо помочь.
Более того, даже при машинной верификации тестирование всё равно необходимо — чтобы повысить шансы, что условия, включённые в аксиоматику верификатора, действительно истинны.
L>TEST(go_around_zero_v2, testNegativeN)
Вот тут уже начинаются нелады. Основная проблема в том, что ты поддался на откровенную провокацию Кодта. Провокация эта не в INT_MIN или в чём-то подобном; провокация в том, что ты согласился рассматривать именно его постановку задачи в виде этой функции и его разбиение кода этой функции на структурные части. А это тут не нужно. Проверка кода в таком виде или вообще не проверяется тестами, или тесты станут повторять последствия математической верификации кода; но тогда им нужно проверять не выходной скомпилированный результат, а промежуточный отчёт компилятора (gcc, например, на каком-то этапе выдаёт возможные границы значений переменных) или вообще исходный код! Это работа статического анализатора, который должен был сказать "эгегей, если у тебя n>214748364, то у тебя проблемы с UB, а если n<0, то вообще непонятно, чего ты тут хотел добиться". То есть всё равно верификатор.
Итого, лучше всего было просто отказаться рассматривать в таком виде.
L> unsigned int expected = n*10*2+1; // Ну или 100500 от балды, чтобы просто отловить бесконечный цикл
Так не отловишь же — оно может захотеть вообще ничего не делать. Да и в реальности бесконечного цикла не будет при любом из возможных переполнений.
Пока что, если ты пишешь тест, уже зная про потенциальную возможность UB, тебе нет смысла писать тест именно на UB именно потому, что UB непредсказуемо и поэтому заведомо за рамками тестирования.
(Разве что апостериорного статистического, но это совсем другой разговор.)
Вот если бы речь шла про C# и checked context, или аналогичное средство, где переполнение гарантируется, можно было бы его явно проверить только зачем? И без нас есть кому проверить компилятор
К>>А в это время в Виллабаджо уже делают фигак-фигак-продакшен.
L>)
L>Через 3 месяца тестеры пишут баг-репорт "падает". Смотришь в лог, видишь bananas. Пинаешь того, кто вызывал твой код.
Всё-таки в контрактах это уместнее.
L>До приемлимой.
На всякий случай — "приемлемой".