Здравствуйте, varenikAA, Вы писали:
AA>Здравствуйте, netch80, Вы писали:
AA>мы явно говорим на разных языках.
Вполне возможно. При этом в вашем языке отсутствуют чёткие определения, слова меняют смысл как вздумается не то говорящему, не то самим словам, и в результате никто не может понять смысл сказанного, и остаётся только кивать "да, я тебя тоже уважаю".
Что ж, есть места, где такой язык вполне уместен. Но данная дискуссия как-то не очень входит в их набор.
Здравствуйте, netch80, Вы писали:
N>Что TDD это неработающая методика (в чистом виде) — я согласен. Любая практика больше одноразового кода его нарушает.
О чем спор тогда?
N>А вот дальше вы начинаете нести полную чушь, игнорируя реальность и устанавливая некорректные логические связи. Потому что:
"Потому что" тут может быть только один — тебе выдали сертификат носителя истины, но ты забыл его привести. Иначе это просто твое частное мнение.
N>1. Программные тесты отображают спецификацию к компоненту и позволяют её проверить автоматизированно в любой момент.
Нет, обычно, не отображают. Да, можно выразить спецификацию через тесты. Так делают через проперти тесты. Проблема с этим подходом только одна: за пределами демонстрационных примеров, типа разворота списка, это сделать достаточно сложно. Во всяком случае в дикой природе встречается в крайне ограниченном виде.
N>Таким образом они ещё и работают регрессионными проверками (если что-то сломали позже, запуск тестов это ловит).
Если бы этот подход работал, то в программе бы не было багов. Вообще. Я думаю ты даже сам в эту "чушь" не веришь. А с чего начинается правильная работа на багом? Правильно, с написания очередного теста для него. Что доказывает неполноту предыдущей спецификации.
N>1) Инверсии — вводится внешняя непрозрачная для логики теста фиксированная модификация, после которой тест может упасть. Проверка заключается в обнаружении планового падения теста. N>2) Мутации — код компонента или код теста меняется случайным образом и это не должно пройти незамеченным.
Ничего из этого не доказывает ни правильность теста, ни полноту спецификации. Теперь и ты знаешь. Не благодари.
Здравствуйте, Sharowarsheg, Вы писали:
N>>>>Вот у меня новая суперсортировка. Я пишу тест: sort([3,2,5,4,1]) == [1,2,3,4,5]. Это дублирование кода сортировки или нет?
ZEN>>>Это сравнение возвращаемой функцией sort() ссылки на объявленный в коде массив. Чего вы этим хотите добиться?
N>>Вы даже не уточнили, о каком языке идёт речь в этом псевдокоде и какое сравнение участвует, а уже пытаетесь буквоедствовать.
S>Это то же самое, что пытаться тестировать, ещё не имея кода.
Ну, я бы сказал, что общего как раз мало.
До кода есть представления о том, что этот код должен делать. Многие из них уже однозначны. Эти представления можно записать формально. Это больше относится к BDD и ATDD, чем TDD, но TDD представляет собой просто введение этой методики в (некорректный) абсолют.
Второе что составляет постулат в TDD — это продвижение мелкими шагами для удовлетворения тестов и только для этого. Это не подходит во многих случаях (в основном это сложные алгоритмические задачи, где не существует промежуточных этапов по одному тесту), и может быть слишком дорого для клеевого кода, но есть много случаев, когда я нашёл это удобным. В частности, это очень хороший путь разбиения объёмной задачи (от объёма которой опускаются руки) до состоящей из мелких, подъёмных задач.
В комбинации они дают весьма удобное средство ставить задачи для постепенного продвижения с написанием кода.
Ну а если абьюзить средство... тут уже приводили множество крайних примеров, не хочется повторяться.
Здравствуйте, Ватакуси, Вы писали:
I>>Может. Это не повод отказываться от тестов. Если убрать юнит-тесты, то простое переименование переменной становится причиной еще большего хаоса.
В>Для этого есть компиляторы или хотя бы стат. анализаторы.
Компиляторы и стат-анализаторы решают совсем другой класс ошибок. Это необходимое условие для рефакторинга, но этого еще не достаточно.
В>Я вот сейчас работаю с проектом, где до одного места этих микросервисов, которые ещё засунуты в самописный велосипед. 80% тестов ничего не тестируют, а просто добавляют "покрытие". В>Там тупо всё mocked.
Именно. Тесты проверяют моки По этой причине для рефакторинга нужно отказываться от моков, а дизайнить компоненты таким образом, что бы у нас был такой расклад
1. много дешевых value-check тестов, т.е. тесты вида expect(sin(x)).to.eq(y). Сюда же относится property-based тесты.
2. компромис — если нет способа как п.1, напримпер, стейтфул-механика, то тестируем через state-check. Разумеестся, если можно отказаться от стейт-фул логики, то все тесты перепиливаются как п.1
3. поведенческие — если нет способа п1 и п2. Вот здесь появляются моки,
п.3 — хрупкие тесты, часто вечнозеленые, дают слабые гарантии, их очень дорого писать.
Собтсвенно, поведенческие хрупкие и ломаются при рефакторинге, наприер, результат обеспечили такой же, но иначе, а вот тест сломался. И такое собтсвенно норма для поведенческих тестов на моках
Такой симптом как обилие моков говорит о том, что неверно выбраны уровни тестирования. Т.е. например, функциональные тесты пишутся на уровне юнит-тестов, а через моки определяем признаки поведения. Ну или наооборот — юниты на уровне функциональных, тогда мок дополнительно изолирует выбранный юнит.
Иногда такое необходимо, но только если дизайн кривой настолько, что трудно реализовать п1 или п2. или же имем дело с 3rd party компонентами, когда дизайн изменить нельзя.
На мой взгляд, поведенческие тесты должны использоваться где то на самых высоких уровнях, когда система собрана полностью и нет нужды в моках. Т.е. проверяем реакцию системы на действия пользователя по наличию тех или иных вещей — залогинился, значит ожидаем, что после этого появился персональный контент, который соответствует именно этому логину. Вылогинился — ожидаем, что этот контент исчез из показа.
Здравствуйте, netch80, Вы писали:
I>> не существует методики ни разработки, ни тестирования, которая может дать гарантию отсутствия ошибок
N>Ну почему же. Формальная верификация даёт такую гарантию — где она применима.
Не дает, т.к. в реализации ты можешь чуточку ошибиться, перепутать = и !=, т.е. минорная ошибка, которая просто портит вывод.
I>>Точно так же и в security не сущетсвует способа дать гарантию отсутствия любых уязвимостей.
N>Есть — полная физическая изоляция
Подловил!!!!111
I>>5. приложение покрывает все известные сценарии, см перечень сценариев I>>6. приложение покрывает все критические кейсы, см перечень кейсов
N>И обычно последние два пункта доводят требования до состояния полной нереализуемости.
Здесь ничего странного. Сценариев обычно немного, несколько десятков или сотен. Это все реализуемо относительно небольшими затратами.
Здравствуйте, Poopy Joe, Вы писали:
PJ>Здравствуйте, netch80, Вы писали:
N>>Что TDD это неработающая методика (в чистом виде) — я согласен. Любая практика больше одноразового кода его нарушает. PJ>О чем спор тогда?
О множестве важных деталей и о расстановке принципиальных акцентов.
N>>А вот дальше вы начинаете нести полную чушь, игнорируя реальность и устанавливая некорректные логические связи. Потому что: PJ>"Потому что" тут может быть только один — тебе выдали сертификат носителя истины, но ты забыл его привести. Иначе это просто твое частное мнение.
Ап ту ю. Можете игнорировать, но потом нарвётесь — вспомните.
N>>1. Программные тесты отображают спецификацию к компоненту и позволяют её проверить автоматизированно в любой момент. PJ>Нет, обычно, не отображают. Да, можно выразить спецификацию через тесты.
Вы пропустили, что не "выражают", а именно "отображают". Отображение ограниченно, но искусство программиста — в умении выбрать тесты, которые отражают и типовые, и крайние случаи.
PJ> Так делают через проперти тесты. Проблема с этим подходом только одна: за пределами демонстрационных примеров, типа разворота списка, это сделать достаточно сложно. Во всяком случае в дикой природе встречается в крайне ограниченном виде.
Дикая природа — она разная бывает. Глубинный океан, тайга и саванна различаются принципиально.
Я аналогичным образом разделяю случаи:
1) Алгоритмические задачи. Например, Quicksort. Писать её согласно TDD как-то совсем нереально.
2) Задачи с принципиально неконкретизируемым ответом, но к которым можно применить другие критерии. Например, нейросеть, которая определяет котиков. Она может пропустить 10% котиков тестового набора, если это дозволено.
3) Простые громоздкие задачи со сложным кодом. Например, парсинг HTTP.
4) Простые громоздкие задачи с простым кодом. Например, релеинг запросов бизнес-модели в операторы SQL и обратное преобразование данных.
Общего решения для них не будет. Некоторые подходы работают для всех, но заметно выгибаются.
И вот, кстати, property-based testing пригодно как минимум для 1, 3 и 4.
И я делал такое использование на практике.
Если считать статистически — то и 2.
N>>Таким образом они ещё и работают регрессионными проверками (если что-то сломали позже, запуск тестов это ловит). PJ>Если бы этот подход работал, то в программе бы не было багов. Вообще. Я думаю ты даже сам в эту "чушь" не веришь.
В ваше утверждение — "Если бы этот подход работал, то в программе бы не было багов" — конечно, не верю. Нет причин в него верить.
Тесты, в отличие от формальной верификации, в принципе не могут покрыть всё. У них и задачи такой нет. Задачи тестов:
1. Показать работоспособность для внешнего контроля (заказчик, QA...), который может вообще не интересоваться тем, что в решении есть программная часть и как она устроена.
2. Дать авторам кода средства поиска ошибок, не найденных никакой верификацией (включая визуальную, как peer review). Критически важно из-за принципиального различия методов работы компьютера и человека (например, человек из-за "замыленного глаза" может в упор не видеть ошибку, и не в состоянии получить результат из 100500 уровней #include).
3. Подтвердить корректность внешних постулатов (например, что open() открывает файл согласно пути и ключам, а не звонит в колокольчик).
И вот именно под решение этих задач их и надо продумывать и писать.
PJ> А с чего начинается правильная работа на багом? Правильно, с написания очередного теста для него. Что доказывает неполноту предыдущей спецификации.
Спецификация меняется под задачи. "Неполнота" предыдущей спецификации, а точнее, вообще её отличие (может что-то вообще меняться несовместимо) — норма разработки. Методология должна это учитывать.
Точно так же она должна учитывать и то, что может оказаться, что под новую спецификацию ничего не надо менять. И так бывает.
N>>1) Инверсии — вводится внешняя непрозрачная для логики теста фиксированная модификация, после которой тест может упасть. Проверка заключается в обнаружении планового падения теста. N>>2) Мутации — код компонента или код теста меняется случайным образом и это не должно пройти незамеченным. PJ>Ничего из этого не доказывает ни правильность теста, ни полноту спецификации. Теперь и ты знаешь.
Про полноту спецификации тезис появился только в вашем последнем комментарии. Полная спецификация или нет — вопрос отдельный и к теме тестов напрямую не относящийся, потому что для программиста требуется предельно точное ТЗ. Я не буду рассматривать этот тезис тут.
Правильность теста — точнее, набора тестов — как раз практически подтверждается (слово "доказывается" тут неуместно).
PJ> Не благодари.
Здравствуйте, Ikemefula, Вы писали:
I>>> не существует методики ни разработки, ни тестирования, которая может дать гарантию отсутствия ошибок N>>Ну почему же. Формальная верификация даёт такую гарантию — где она применима. I>Не дает, т.к. в реализации ты можешь чуточку ошибиться, перепутать = и !=, т.е. минорная ошибка, которая просто портит вывод.
Этого не понял — это для какого языка так?
Если описано внешнее требование, то существенные ошибки приведут к нарушению доказательства.
I>>>Точно так же и в security не сущетсвует способа дать гарантию отсутствия любых уязвимостей. N>>Есть — полная физическая изоляция I>Подловил!!!!111
Ага
а если серьёзно — то все уязвимости надо формализовать.
Есть принципиально неустранимые за счёт самого факта доступа.
И отличие проблем "не заткнули известный канал атаки" от "не учли все каналы атаки" принципиально — первое это вопрос корректности кода, а второе это уже не к программистам. Прикладной код не обязан защищаться от Meltdown
I>>>5. приложение покрывает все известные сценарии, см перечень сценариев I>>>6. приложение покрывает все критические кейсы, см перечень кейсов N>>И обычно последние два пункта доводят требования до состояния полной нереализуемости.
I>Здесь ничего странного. Сценариев обычно немного, несколько десятков или сотен. Это все реализуемо относительно небольшими затратами.
Хм, попытался подсчитать сценарии в своём текущем продукте — со всеми вариациями идёт на десятки тысяч.
А всего-то: паркинг против пикапа, транскодинг/трансрейтинг данных, прохождение NAT, темпы реавторизации, ещё десяток факторов...
и разделить, зараза, нельзя толком...
Здравствуйте, netch80, Вы писали:
N>О множестве важных деталей и о расстановке принципиальных акцентов.
И в чем заключаются эти акценты?
N>Ап ту ю. Можете игнорировать, но потом нарвётесь — вспомните.
Нарвусь на что? Я очень переживаю о том считаешь ли ты мои слова чушью, это крайне важно для меня.
N>Вы пропустили, что не "выражают", а именно "отображают". Отображение ограниченно, но искусство программиста — в умении выбрать тесты, которые отражают и типовые, и крайние случаи.
И что это отображение дает?
N>И вот, кстати, property-based testing пригодно как минимум для 1, 3 и 4.
Оно пригодно для всех четырех. В теории. На практике какой процент у тебя таких тестов в общем коде? Вот, то-то и оно.
N>В ваше утверждение — "Если бы этот подход работал, то в программе бы не было багов" — конечно, не верю. Нет причин в него верить.
Я не просил верить в мое утверждение. Я спросил веришь ли ты что в программе нет багов. По определению, если тесты описывают спецификацию и они зеленые, то багов нет. Так ведь? Не?
N>Тесты, в отличие от формальной верификации, в принципе не могут покрыть всё. У них и задачи такой нет. Задачи тестов:
Задача тестов одна, я ее упоминал выше. Отслеживать изменение поведение кода при рефакторинге. Т.е. это автоматизация рутинной работы. Все! Они совершенно ничего не гарантируют и никогда на это нельзя полагаться. Просто несколько облегчает жизнь.
N>1. Показать работоспособность для внешнего контроля (заказчик, QA...), который может вообще не интересоваться тем, что в решении есть программная часть и как она устроена.
Поржал. Сдаешь заказчику программу и на демо показываешь, что все тесты пройдены?
N>3. Подтвердить корректность внешних постулатов (например, что open() открывает файл согласно пути и ключам, а не звонит в колокольчик).
Есть он будет звонить в колокольчик и открывать файл, то твой тест это скорее всего и не заметит.
N>Спецификация меняется под задачи. "Неполнота" предыдущей спецификации, а точнее, вообще её отличие (может что-то вообще меняться несовместимо) — норма разработки. Методология должна это учитывать. N>Точно так же она должна учитывать и то, что может оказаться, что под новую спецификацию ничего не надо менять. И так бывает.
Ниче не понял. Баг это когда ожидается одно, а результат другой. Никакая спецификация тут не меняется.
N>Про полноту спецификации тезис появился только в вашем последнем комментарии.
Потому я отвечал на пост в котором появилось слово спецификация. Внезапно.
N> Полная спецификация или нет — вопрос отдельный и к теме тестов напрямую не относящийся, потому что для программиста требуется предельно точное ТЗ. Я не буду рассматривать этот тезис тут.
Спецификация, в контексте обсуждения, это описание инварианта функции, которую ты тестируешь. Причем тут "предельно точное ТЗ" и где ты такие вообще видел?
N>Разделение на юнит-тесты и интеграционные — терминологическая нелепость.
Не согласен, ибо если для первых полно соотв. библиотек и т.п. , то для второго все индивидуально.
N>"Модуль" может состоять из других модулей хоть в 10 уровней иерархии. N>Есть функциональные тесты разного уровня. Для всех внутренние сущности работают как обычно (ну, с поправкой на то, что, например, логгинг может быть отключен или иначе настроен), а внешние мокаются или эмулируются (разница тут неважна). По отношению ко внутренним составляющим это интеграционные тесты, а по отношению к внешним — юнит-тесты. Ну и зачем?
Даже индивидуальный сервис может мокать, например, фс (io). Почему нет? Речь идет об идеологии юнит-тестов -- максимально
абстрагироваться от внешнего мира и сосредоточится только на bl.
Здравствуйте, Poopy Joe, Вы писали:
N>>В ваше утверждение — "Если бы этот подход работал, то в программе бы не было багов" — конечно, не верю. Нет причин в него верить. PJ>Я не просил верить в мое утверждение. Я спросил веришь ли ты что в программе нет багов. По определению, если тесты описывают спецификацию и они зеленые, то багов нет. Так ведь? Не?
Конечно, нет. Может, у тебя один тест, который проверяет, как main() разбирает аргументы, и он зелёный
Для того, чтобы с достаточной уверенностью доверять результатам тестов, нужно:
1) Разумность самих тестов (метода, набора тестовых данных), с точки зрения нахождения проблем реализации согласно задаче и выбранному методу.
2) Верификация кода (хотя бы визуальная) на то, что реализован действительно нужный подход (а не поставлен, грубо говоря, большой if на конкретные тестируемые случаи).
3) Достаточное покрытие нужного-по-ТЗ кода тестами (несмотря на всю условность этого понятия).
4) Доверие среде и библиотекам.
Вот после этого можно говорить — не абсолютно, но с практически достаточной уверенностью — про отсутствие багов.
И да, в это я верю. Как-то практика показывает, что именно так и оно и работает
N>>Вы пропустили, что не "выражают", а именно "отображают". Отображение ограниченно, но искусство программиста — в умении выбрать тесты, которые отражают и типовые, и крайние случаи. PJ>И что это отображение дает?
Даёт пункт (1) в списке выше.
N>>И вот, кстати, property-based testing пригодно как минимум для 1, 3 и 4. PJ>Оно пригодно для всех четырех. В теории. На практике какой процент у тебя таких тестов в общем коде? Вот, то-то и оно.
В зависимости от задачи сильно по-разному.
Были, где, грубо говоря, 90%. Сейчас крайне мало — но это потому, что ресурсов нет. А так я бы и сейчас добавил переменных.
N>>Тесты, в отличие от формальной верификации, в принципе не могут покрыть всё. У них и задачи такой нет. Задачи тестов: PJ>Задача тестов одна, я ее упоминал выше. Отслеживать изменение поведение кода при рефакторинге.
Если ты используешь тесты ровно для этого — это твои личные ограничения.
PJ> Т.е. это автоматизация рутинной работы. Все! Они совершенно ничего не гарантируют и никогда на это нельзя полагаться. Просто несколько облегчает жизнь.
Не "несколько", а на порядки.
И не "совершенно ничего не гарантируют", а гарантируют поиск >90% багов в обычном применении. Конкретная доля может быть и 95, и 99%, в зависимости от множества факторов.
Как по мне, этого достаточно, чтобы тратить на них приличный кусок времени (условно говоря, половину).
N>>1. Показать работоспособность для внешнего контроля (заказчик, QA...), который может вообще не интересоваться тем, что в решении есть программная часть и как она устроена. PJ>Поржал. Сдаешь заказчику программу и на демо показываешь, что все тесты пройдены?
А почему ты в этом рассмотрении предполагаешь только внутренние кодовые тесты?
Они могут быть и визуальные, и в режиме чёрного ящика "X на входе — Y на выходе", и массой промежуточных вариантов.
N>>3. Подтвердить корректность внешних постулатов (например, что open() открывает файл согласно пути и ключам, а не звонит в колокольчик). PJ>Есть он будет звонить в колокольчик и открывать файл, то твой тест это скорее всего и не заметит.
Это ловится на других уровнях и другими методами.
N>>Спецификация меняется под задачи. "Неполнота" предыдущей спецификации, а точнее, вообще её отличие (может что-то вообще меняться несовместимо) — норма разработки. Методология должна это учитывать. N>>Точно так же она должна учитывать и то, что может оказаться, что под новую спецификацию ничего не надо менять. И так бывает. PJ>Ниче не понял. Баг это когда ожидается одно, а результат другой. Никакая спецификация тут не меняется.
А кто только что писал про предыдущую спецификацию? Сам уже не помнишь, что писал?
N>>Про полноту спецификации тезис появился только в вашем последнем комментарии. PJ>Потому я отвечал на пост в котором появилось слово спецификация. Внезапно.
OK. Представим себе, что "спецификация" это "полное и точное ТЗ", и пойдём дальше. Так откуда взялась предыдущая спецификация?
N>>О множестве важных деталей и о расстановке принципиальных акцентов. PJ>И в чем заключаются эти акценты?
Ну вот я выше и описал. Разница между "ничего не гарантируют" и "статистически гарантируют поиск >90% ошибок", по-твоему, важна или нет?
N>>Ап ту ю. Можете игнорировать, но потом нарвётесь — вспомните. PJ>Нарвусь на что? Я очень переживаю о том считаешь ли ты мои слова чушью, это крайне важно для меня.
Сарказм понят, но не оценён. Нарвёшься на то, что будешь отказываться от доступных средств из-за гордыни.
Здравствуйте, Sharov, Вы писали:
N>>Разделение на юнит-тесты и интеграционные — терминологическая нелепость. S>Не согласен, ибо если для первых полно соотв. библиотек и т.п. , то для второго все индивидуально.
Если у тебя есть функция со входом и выходом, то неважно, сколько внутри себя она вызывает других функций — она будет тестироваться как нечто, что получает аргументы и отдаёт результаты.
N>>"Модуль" может состоять из других модулей хоть в 10 уровней иерархии. N>>Есть функциональные тесты разного уровня. Для всех внутренние сущности работают как обычно (ну, с поправкой на то, что, например, логгинг может быть отключен или иначе настроен), а внешние мокаются или эмулируются (разница тут неважна). По отношению ко внутренним составляющим это интеграционные тесты, а по отношению к внешним — юнит-тесты. Ну и зачем?
S>Даже индивидуальный сервис может мокать, например, фс (io). Почему нет? Речь идет об идеологии юнит-тестов -- максимально S>абстрагироваться от внешнего мира и сосредоточится только на bl.
Ну а интеграционные, что, не абстрагируются от внешнего мира?
Или речь про проведение границы между "чистыми" и "нечистыми" функциями?
Здравствуйте, netch80, Вы писали:
N>Если у тебя есть функция со входом и выходом, то неважно, сколько внутри себя она вызывает других функций — она будет тестироваться как нечто, что получает аргументы и отдаёт результаты.
Это таки важно, если идет обращение к другим модулям\сервисам. Иной раз задолбаешься все поднимать. Замокал и тестируй себе.
S>>Даже индивидуальный сервис может мокать, например, фс (io). Почему нет? Речь идет об идеологии юнит-тестов -- максимально S>>абстрагироваться от внешнего мира и сосредоточится только на bl.
N>Ну а интеграционные, что, не абстрагируются от внешнего мира?
Ну это почти боевая эксплуатация, т.е. как реальный пользователь будет взаимодействовать с системой.
N>Или речь про проведение границы между "чистыми" и "нечистыми" функциями?
Здравствуйте, Sharov, Вы писали:
N>>Ну а интеграционные, что, не абстрагируются от внешнего мира? S>Ну это почти боевая эксплуатация, т.е. как реальный пользователь будет взаимодействовать с системой. N>>Или речь про проведение границы между "чистыми" и "нечистыми" функциями? S>В некотором роде да, речь про изоляцию.
Как-то всё это абстрактно. Вот у меня есть:
1. Transport layer.
2. Transaction layer, использует transport layer.
3. Dialog layer, использует transaction layer.
Остановимся на этом (там ещё уровня 4, но не усложняем).
Transport layer незамоканный отправляет в сеть и принимает; замоканный зовёт нужные коллбэки.
Уровень транзакций незамоканный общается с транспортным, замоканный дёргает вызовы некоего мока.
Ну и с третьим точно так же.
Если я тестирую диалоговый уровень — что например по получению "200 OK" произошёл переход состояния объекта Dialog из Trying или Early в Confirmed, и посылаю это как вызов processResponse() от транзакционного модуля, это юнит-тест?
А если я сделаю то же самое, сэмулировав сетевой ответ от транспорта (тогда у транзакционного его processIncoming() опознает ответ, заматчит транзакцию, найдёт коллбэк диалога в её состоянии и вызовет его), это ещё юнит-тест или уже интеграционный?
А если я реально пришлю UDP пакет в транспорт, это уже интеграционный тест или ещё нет?
А если это будет TLS поверх TCP (расшифровка которого делается в third-party в лице OpenSSL)?
С моей точки зрения, это всё функциональные тесты, и пофиг, что из них считать "юнитами". А как в остальном мире?
N>Конечно, нет. Может, у тебя один тест, который проверяет, как main() разбирает аргументы, и он зелёный
Во, ты начинаешь что-то подозревать. Прикол в том, что это ничем не отличается ни от 1000, ни от 10000.
N>1) Разумность самих тестов (метода, набора тестовых данных), с точки зрения нахождения проблем реализации согласно задаче и выбранному методу.
И как ты проверяешь разумность?
N>2) Верификация кода (хотя бы визуальная) на то, что реализован действительно нужный подход (а не поставлен, грубо говоря, большой if на конкретные тестируемые случаи).
Жесть какая...
N>3) Достаточное покрытие нужного-по-ТЗ кода тестами (несмотря на всю условность этого понятия).
Достаточное это какое?
N>4) Доверие среде и библиотекам.
А нафига тогда все предыдущие?
N>Вот после этого можно говорить — не абсолютно, но с практически достаточной уверенностью — про отсутствие багов.
И че хоть раз такое происходило? Ну, только честно.
N>И да, в это я верю. Как-то практика показывает, что именно так и оно и работает
В стране с единорогами?
N>Были, где, грубо говоря, 90%. Сейчас крайне мало — но это потому, что ресурсов нет. А так я бы и сейчас добавил переменных.
Охотно верю, был демо проект, где 90% и реальный код, где их почти нет. Я ровно об этом.
N>Если ты используешь тесты ровно для этого — это твои личные ограничения.
Увы, не мои. Это ограничение самой методики. Вот честно, хотелось бы иметь волшебную технологию уровня "компилируется — в продакшн"
N>А почему ты в этом рассмотрении предполагаешь только внутренние кодовые тесты?
Потому что речь о ТDD. Впрочем, заказчика вообще никакие тесты не интересуют. Я, по-крайней мере, таких не видел.
N>Это ловится на других уровнях и другими методами.
Какими?
N>А кто только что писал про предыдущую спецификацию? Сам уже не помнишь, что писал?
Я вообще не понял, что ТЫ написал. Я либо впервые использовал слово спецификация, либо использовал его до этого. Оба утверждения твои и оба они не могут быть верными одновременно.
N>OK. Представим себе, что "спецификация" это "полное и точное ТЗ", и пойдём дальше. Так откуда взялась предыдущая спецификация?
I'm lost. Полное и точное ТЗ, это функциональные требования к системе, это функциональные тесты, в лучшем случае.
Спецификация о которой идет речь это спецификация на отдельные куски кода, которые ты покрываешь тестами. Представим, что теплое это мягкое и пойдем дальше.
N>Ну вот я выше и описал. Разница между "ничего не гарантируют" и "статистически гарантируют поиск >90% ошибок", по-твоему, важна или нет?
Нет, разумеется. Гарантия понятия бинарное, она либо есть, либо ее нет. И нет, тесты этого не гарантируют. Все что гарантируют тесты, это если у тебя измениться поведение функции которую проверяет тест, при условии, что тест проверяет конкретный случай, то он это покажет.
N>Сарказм понят, но не оценён. Нарвёшься на то, что будешь отказываться от доступных средств из-за гордыни.
От каких доступных средств я отказываюсь? От тестов? Это ты сам придумал.
От построения из них карго-культа? Так это ты нарвешься, думая, что они тебе чего-то там гарантируют.
Здравствуйте, netch80, Вы писали:
PJ>>Задача тестов одна, я ее упоминал выше. Отслеживать изменение поведение кода при рефакторинге. N>Если ты используешь тесты ровно для этого — это твои личные ограничения.
А для чего еще нужно использовать юнит-тесты кроме как "локально" корректности кода? Ловить
проблемы при рефакторинге или изменении BL.
N>Transport layer незамоканный отправляет в сеть и принимает; замоканный зовёт нужные коллбэки. N>Уровень транзакций незамоканный общается с транспортным, замоканный дёргает вызовы некоего мока. N>Ну и с третьим точно так же. N>Если я тестирую диалоговый уровень — что например по получению "200 OK" произошёл переход состояния объекта Dialog из Trying или Early в Confirmed, и посылаю это как вызов processResponse() от транзакционного модуля, это юнит-тест?
Да.
N>А если я сделаю то же самое, сэмулировав сетевой ответ от транспорта (тогда у транзакционного его processIncoming() опознает ответ, заматчит транзакцию, найдёт коллбэк диалога в её состоянии и вызовет его), это ещё юнит-тест или уже интеграционный?
Я бы сказал да. Ну точно не интеграционный.
N>А если я реально пришлю UDP пакет в транспорт, это уже интеграционный тест или ещё нет?
Интеграционный тест. Проверяем все целиком, т.е. вполне реальное взаимодействие. Т.е. если провели
с сетевой картой, то тест упадет.
N>А если это будет TLS поверх TCP (расшифровка которого делается в third-party в лице OpenSSL)?
Зависит от, см. выше. Если хоть что-то замокано, то не интеграционный точно.
N>С моей точки зрения, это всё функциональные тесты, и пофиг, что из них считать "юнитами". А как в остальном мире?
Здравствуйте, Poopy Joe, Вы писали:
N>>Вот после этого можно говорить — не абсолютно, но с практически достаточной уверенностью — про отсутствие багов. PJ>И че хоть раз такое происходило? Ну, только честно.
Постоянно происходит, честно.
Например, QA в очередном релизе отловил 20 багов; у кастомеров сработало ещё 10; перед этим запуском в Jenkins было поймано и исправлено 300-400.
Перед этим ещё 100 (народ достаточно ленив) поймано самими программистами, в варианте "вот я наверно это сломаю... пойду запущу сразу, не дожидаясь получасового прогона всех тестов".
Цифры меняются, соотношение примерно похоже на это.
Ну а так как цена отлова бага на стадии CI в десятки раз меньше такого же на кастомере (не считая потерь самого кастомера), то можно было бы и 95% времени тратить на тесты. Это уже не получается — не организуешь людей на это.
N>>Ну вот я выше и описал. Разница между "ничего не гарантируют" и "статистически гарантируют поиск >90% ошибок", по-твоему, важна или нет? PJ>Нет, разумеется. Гарантия понятия бинарное, она либо есть, либо ее нет. И нет, тесты этого не гарантируют. Все что гарантируют тесты, это если у тебя измениться поведение функции которую проверяет тест, при условии, что тест проверяет конкретный случай, то он это покажет.
Ну вот пока ты будешь так думать, будешь предельно непрактичен.
И я не зря "подпёр" полезность тестов условием верификации кода.
N>>И да, в это я верю. Как-то практика показывает, что именно так и оно и работает PJ>В стране с единорогами?
Реальные проекты, реальные люди со всеми их проблемами.
Просто систему наладили и она кое-как, подпрыгивая на ухабах, но постоянно движется вперёд.
Единорогов не впрягали, за неимением таковых.
N>>Конечно, нет. Может, у тебя один тест, который проверяет, как main() разбирает аргументы, и он зелёный PJ>Во, ты начинаешь что-то подозревать. Прикол в том, что это ничем не отличается ни от 1000, ни от 10000. N>>1) Разумность самих тестов (метода, набора тестовых данных), с точки зрения нахождения проблем реализации согласно задаче и выбранному методу. PJ>И как ты проверяешь разумность?
По каждому случаю отдельно.
Вот пример (не мой): у процессора нет операции умножения, надо её сэмулировать. Делается вариант 16*16->16 с откидыванием старшей части. Знаем, что будет какой-то цикл по битам.
Добавляем тесты: 0*0 -> 0, 1*0 -> 0, 1*1 -> 1, 2*0 -> 0, 0*2 -> 0, 2*2 -> 4, 2*-2 -> -4, -2*2 -> -4, 2*2 -> 4.
Ещё парочку базовых, типа 137*73 -> 10001.
На переполнение: 256*256 -> 0, 257*257 -> 513, -32768*3 -> -32768...
Пара десятков таких тестов покроет и базовую функциональность, и маргинальные случаи, с запасом на все типовые алгоритмы.
N>>2) Верификация кода (хотя бы визуальная) на то, что реализован действительно нужный подход (а не поставлен, грубо говоря, большой if на конкретные тестируемые случаи). PJ>Жесть какая...
Что удивляет-то? Никогда peer review не проходил? Ну, всё впереди.
N>>3) Достаточное покрытие нужного-по-ТЗ кода тестами (несмотря на всю условность этого понятия). PJ>Достаточное это какое?
100% хотя бы одним тестом каждого куска кода основного пути выполнения.
Не считаются те, которые вызываются плохо предсказуемыми внешними условиями, хотя и их можно на следующем круге замокать.
N>>4) Доверие среде и библиотекам. PJ>А нафига тогда все предыдущие?
Ну мало ли. Вдруг в следующей версии починят? )
N>>Были, где, грубо говоря, 90%. Сейчас крайне мало — но это потому, что ресурсов нет. А так я бы и сейчас добавил переменных. PJ>Охотно верю, был демо проект, где 90% и реальный код, где их почти нет. Я ровно об этом.
Это у тебя демо, а у меня был полностью реальный.
N>>Если ты используешь тесты ровно для этого — это твои личные ограничения. PJ>Увы, не мои. Это ограничение самой методики. Вот честно, хотелось бы иметь волшебную технологию уровня "компилируется — в продакшн"
Ограничения у методики есть, но сильно дальше, чем ты их видишь.
N>>А почему ты в этом рассмотрении предполагаешь только внутренние кодовые тесты? PJ>Потому что речь о ТDD.
Нет, не только.
PJ> Впрочем, заказчика вообще никакие тесты не интересуют. Я, по-крайней мере, таких не видел.
Ну я видел, и работал с. И ты не учитываешь внутреннего заказчика в продукте.
N>>Это ловится на других уровнях и другими методами. PJ>Какими?
Да хоть ручной проверкой. Это уже не наша задача.
N>>А кто только что писал про предыдущую спецификацию? Сам уже не помнишь, что писал? PJ>Я вообще не понял, что ТЫ написал. Я либо впервые использовал слово спецификация, либо использовал его до этого. Оба утверждения твои и оба они не могут быть верными одновременно.
Я про предыдущую спецификацию вроде не писал первый.
N>>OK. Представим себе, что "спецификация" это "полное и точное ТЗ", и пойдём дальше. Так откуда взялась предыдущая спецификация? PJ>I'm lost. Полное и точное ТЗ, это функциональные требования к системе, это функциональные тесты, в лучшем случае. PJ>Спецификация о которой идет речь это спецификация на отдельные куски кода, которые ты покрываешь тестами. Представим, что теплое это мягкое и пойдем дальше.
Ну у тебя почему-то ТЗ это сверху, а спецификация это снизу. Я не вижу причин так делить.
N>>Сарказм понят, но не оценён. Нарвёшься на то, что будешь отказываться от доступных средств из-за гордыни. PJ>От каких доступных средств я отказываюсь? От тестов? Это ты сам придумал. PJ>От построения из них карго-культа? Так это ты нарвешься, думая, что они тебе чего-то там гарантируют.
Я получаю с них реальную пользу — баги ловятся задолго до попадания к кастомеру. А ты можешь продолжать искать и требовать воздушные замки.
Здравствуйте, netch80, Вы писали:
N>Постоянно происходит, честно.
Как это сочетается с следующим предложением? N>Например, QA в очередном релизе отловил 20 багов; у кастомеров сработало ещё 10;
N> перед этим запуском в Jenkins было поймано и исправлено 300-400. Вам надо ваш процесс переименовать с разработки через тестирование, на разработку через багфиксы.
N>Цифры меняются, соотношение примерно похоже на это.
Ну, я хотя бы понял, что у вас называется "отсутствием багов". Оказалось, что просто общаемся из разных планов бытия.
N>Ну вот пока ты будешь так думать, будешь предельно непрактичен.
Возможно, зато у нас кастомеры не ловят в "безбаговых" продуктах по 10 багов + еще хрен знает сколько не пойманых.
N>Единорогов не впрягали, за неимением таковых.
Угу, у вас вместо них кастомеры.
N>Что удивляет-то? Никогда peer review не проходил? Ну, всё впереди.
Ты ща начал размером опыта давить что ли? Не стоит.
Я никогда не видел, чтобы ревью чего-то доказывало. Особенно уровня "у тебя тут if не хватает".
N>100% хотя бы одним тестом каждого куска кода основного пути выполнения.
Понятно, тесты ради тестов, покрытие, ради покрытия.
N>Не считаются те, которые вызываются плохо предсказуемыми внешними условиями, хотя и их можно на следующем круге замокать.
Ты хоть и не просил, но бесплатный совет: когда ты видишь, что тебя надо что-то мокать — ты видишь у себя неправильный дизайн.
N>Нет, не только.
Ну может ты еще о чем-то своем, но я говорил о разработке через тестирование.
N>Ну я видел, и работал с. И ты не учитываешь внутреннего заказчика в продукте.
Нет конечно, им точно так же похрен на твои тесты.
N>Да хоть ручной проверкой. Это уже не наша задача.
Что не твоя задача? Качество? Тогда зачем париться с тестами?
N>Я про предыдущую спецификацию вроде не писал первый.
Слово спецификация впервые употребил ты. http://rsdn.org/forum/flame.comp/8032039.1
Если ты тестами описываешь спецификацию, то новый тест спецификацию расширяет/меняет, поэтому старая она становится предыдущейю. Не бог весть какая логика. Дальше я твою мысль не понимаю вообще.
N>Ну у тебя почему-то ТЗ это сверху, а спецификация это снизу. Я не вижу причин так делить.
Ты опять чего-то выдумываешь. Я не употреблял слова верх или низ.
N>Я получаю с них реальную пользу — баги ловятся задолго до попадания к кастомеру. А ты можешь продолжать искать и требовать воздушные замки.
Ага, я вижу.
Здравствуйте, Poopy Joe, Вы писали:
N>> перед этим запуском в Jenkins было поймано и исправлено 300-400. PJ> Вам надо ваш процесс переименовать с разработки через тестирование, на разработку через багфиксы. N>>Цифры меняются, соотношение примерно похоже на это. PJ>Ну, я хотя бы понял, что у вас называется "отсутствием багов". Оказалось, что просто общаемся из разных планов бытия.
Это очень прикольно, учитывая, что 1) я никогда не говорил, что ведём "разработку через тестирование", 2) никогда не утверждал отсутствие багов как результат применения тестов.
С кем ты тут споришь — не знаю, но это не я. Кто там у тебя на твоём плане бытия — не в курсе.
На этом я прекращаю. Продолжение будет возможно с собеседником, который общается со мной, а не с неизвестными астральными проекциями.
Здравствуйте, netch80, Вы писали:
N>Это очень прикольно, учитывая, что 1) я никогда не говорил, что ведём "разработку через тестирование", 2) никогда не утверждал отсутствие багов как результат применения тестов.
Для того, чтобы с достаточной уверенностью доверять результатам тестов, нужно:
1) Разумность самих тестов (метода, набора тестовых данных), с точки зрения нахождения проблем реализации согласно задаче и выбранному методу.
2) Верификация кода (хотя бы визуальная) на то, что реализован действительно нужный подход (а не поставлен, грубо говоря, большой if на конкретные тестируемые случаи).
3) Достаточное покрытие нужного-по-ТЗ кода тестами (несмотря на всю условность этого понятия).
4) Доверие среде и библиотекам.
Вот после этого можно говорить — не абсолютно, но с практически достаточной уверенностью — про отсутствие багов.
Погоди, перед тем как уйдешь, позови, пожалуйста, того, кто писал эту цитату с твоего аккаунта.