Здравствуйте, Pauel, Вы писали:
P>·>Способ экономии ресурсов.
P>Имено — за счет покрытия.
За счёт разделения слона на части.
P>>>Вы отказываетесь идти дальше, и делать внятное покрытие e2e, и посмеиваетесь с тех, кто всё таки покрывает эти 99% как следует.
P>·>Скорее завидую простоте системы, что её реально покрыть e2e на 99%.
P>Вы сами себя ограбили когда строили вашу пирамиду тестов в виде трапеции — полуинтеграционные на моках + конформанс, которые к вашей системе имеют слабое отношение.
В чём ограбили? На прогон тестов и релиз мы тратим как лохи всего пол часа и уныло идём домой, скучаем на прод-саппорте, когда за углом тесты гоняют неделями и нон-стоп вечеринка в проде с юзерами?
P>>>Пример у вас есть внятный? Мне непонятно, каким чудом моки репозитория помогут понять, что же с интеграцией не так.
P>·>Они не для этого.
P>В том то и дело — вы оставили себе только полуинтеграционные тесты на моках.
P>Юнит-тесты вы не пишете, т.к. "это детали реализации, их не надо писать"
Юнит-тесты с моками — это тоже юнит-тесты. Ты до сих пор не въехал что такое моки и как ими надо пользоаться.
P>e2e "слишком долго"
Потому что очень много компонент в системе. Разворачивается на кластере в пол сотни машин. Гонять там проверки каждого поля на null просто невозможно.
P>·>Конф-тесты тестируют чужое api. Система (по крайней мере её прод-часть) не принимает участие в конф-тестах.
P>Про то и речь — про интеграцию ваших компонентов с другими вашими же компонентами они ничего не говорят.
Есть тесты репо + бд — они тестируют интеграцию нашей системы с бд и адеквтатность репо-моков. Есть тесты бл + репо-моки — которые не требуют субд/сокетов/етс и работают быстро.
Можно тесты репо+бд назвать неким подвидом конф-тестов, т.к. субд — это внешняя зависимость по сути.
P> И так со всеми действиями согласно сценарию до самого последнего.
Всё красиво, но медленно. Такой один сценарий отрабатывает e2e секунды, может даже минуты. Пока браузер откроется, пока поля введутся, кнопочки всякие кликаются, установятся сессии по разным каналам, подпишутся очереди и т.п. Сложно иметь много таких тестов.
P>Если вы моками нарезали весь этот путь на части, вы знаете, что внутри каждой из частей всё хорошо
P>А вот склейку всех частей тестируют тесты системного уровня, например, те самые e2e
Угу. Но они не могут тестировать все сценарии, времени не хватит как минимум.
А ещё всякие завязанные на реальное время тесты. Как ты e2e будешь тестировать, что через 30 минут неактивностии юзера происходит логаут? Будешь ждать по пол часа каждый раз?
P>>>Наоборот, e2e показывает те ошибки, которые проходят мимо ваших моков.
P>·>Если оно это показывает случайно, через несколько часов — то это называется хрень, а не показания.
P>Это намного лучше, чем их отсутствие.
Если это действительно намного лучше, это значит что у вас внизу пирамиды дыры зияют.
P>>> Они показывают, что приложение склеено как положено.
P>·>Это и проблема твоего подхода — у тебя в приложении на строчку кода ведро клея, который никак и не тестируется, кроме как тонной e2e.
P>Обратите внимание — сколько бы я вам ни говорил про юнит-тесты и интеграционные, вы всё равно видите своё.
Потому что ты жонглируешь терминологией в соседних предожениях.
P>Вы выбросили:
Ты сочиняешь. Не выбросили. Пирамида такая и есть по форме.
Моки этому всему ортогональны. Они могут быть на любом уровне. Ещё раз, это тупо способ протаскивать данные, альтернатива параметрам.
P>Итого — от вашей пирамиды остался поясок стыдливости
Бредишь.
P>>>Ну да — вы забили на интеграционные тесты.
P>·>Ну так в моём подходе этой интеграции кот наплакал, поэтому "приложение не упало при старте" уже практически означает, что 100% тех ошибок, "которые проходят мимо ваших моков" показано.
P>Это иллюзия. В сложном приложении интеграция не может быть простой, по определению.
Не знаю что ты тут подразумеваешь. Обычно вся интеграция происходит в composition root wiring коде, который составляет доли процента от кодовой базы.
У тебя да — кода интеграции дохрена, вот и проблемы с тестированием.
P>Если у вас есть несколько источников данных для времени, то нужно гарантировать, что все они прописаны корректно для соответствующих юз кейсов
Рассказывал же уже. Коррекность проверяется с помощью моков, подсовываем разное время в разные источники чтобы их можно было различать в тестах.
P>Как это проверяется стартом приложения — не ясно.
Я вроде всё расписал с примерами кода. Перечитай если всё ещё неясно, вопросы задавай чего неясно.
P>>>·>Не годится. Мы не можем релизиться только с тремя десятками сценариев. Надо проверять 100%.
P>>>Я ж вам не предлагаю выбросить — я вам предлагаю добавить, и показываю, как именно.
P>·>Добавлять тест, который запускается рандомно через раз — это какое-то извращение. Если некий тест запускать не обязательно для релиза, клиенты переживут и так — накой его вообще запускать?
P>Вы и запускаете его для релиза — только результаты собираете не разово, а в течение первых часов после деплоя.
P>Здесь важно обнаружить проблемы раньше юзеров на проде.
Через несколько секунд после релиза юзеры на проде уже могут иметь проблемы. Ещё раз. Мы не можем себе повзолить трогать чего-либо в проде до прогона всех тестов.
P>Очевидно, что если собирать сведения не раз. а несколько часов, то сведений будет больше, и диагностика будет точнее
И эти несколько часов у юзеров будут проблемы на проде.
P>>>Вы уже релизитесь без 99%. Если к вашим тестами добавите e2e, то покрытие станет плотнее.
P>·>Не станет.
P>e2e регулярно находят проблемы которые другими тестам даже обнаружить сложно.
Это потому что у вас беда с другими тестами. У нас в точности наоборот, вся та небольшая кучка e2e в подавляющем большинстве случаев просто работает на стейдже. А тот практически единственный TiL тест в худшем случае обнаруживет железные проблемы в инфре.
P>>>Если не хватает времени — e2e можно гонять и после деплоймента, хоть круглые сутки, они хлеба не просят.
P>·>Зачем? Если они что-то обнаружат, это значит что у клиентов проблемы прямо сейчас, prod incident. Поздно борожоми пить.
P>Затем, что бы
P>1 обнаружить на самых ранних этапах
"после деплоймента" — это для нас очень поздний этап. Сразу после деплоя мы идём домой, какой к хрену круглые сутки?
P>2 сразу собрать максимальное количество сведений. По этим тестам у вас больше всего сведений, как и что воспроизвестир
Мы собираем сведения ещё до планирования деплоя.
P>1 репортают проблемы
Это уже полный провал. Будут разборки.
P>·>Ещё раз. Если ты догадался нечто описать в виде теста, пусть e2e — это значит какой-то вполне определённый известный сценарий. Всегда есть возможность покрыть этот сценарий покрыть более дешёвыми тестами и выполнять до релиза, всегда, а не по броску монеты.
P>Сценарии и так покрыты дешовыми тестами. Эти дешовые тесты, особенно на моках, не покрывают всю интеграцию, что очевидно.
Все условно полторы строчки интеграции? Какой ужас!
P>>>Это способ выполнять те тесты, которые у вас вообще отсутствуют.
P>·>Потому что нахрен не нужны.
P>Вот это ваш самый частый аргумент вместе с "словоблудие" итд
Конечно, ибо есть более надёжные и адектватные подходы. Надеяться что юзеры репортают проблемы — это уже дно какое-то.
P>>>Вы тестируете минимально, репозиторий + бд. Эта часть есть и у меня.
P>·>Где конкретно эта часть есть у тебя? Ты заявлял, что в твоих pattern-тестах ты репозиторий + бд не тестируешь; а в e2e ты каждую переменную на null тестирвать не будешь, да и не сможешь.
P>Там же где и у вас — это часть интеграционных тестов.
Т.е. у тебя есть ровно те же "репозиторий + бд" тесты?
P>>>Комбинации различных условий в фильтре, что дает нам ту самую data complexity, и проблемные комбинации вы будете узнавать только на проде, одну за другой
P>·>Ты тоже.
P>Именно. И я этим знанием пользуюсь, а вы — нет. например, я точно знаю, как выглядит проблема с фильтрами — вгружается вообще всё.
А я не знаю такой проблемы... не было у нас такой. ЧЯДНТ?
P>Соответсвенно вариантов решения у меня несколько
P>Даже если я не знаю комбинации, то могу подстараховаться пост-условием
P>А что бы пост-условие не потерялось, подкидываю тест
Ещё молитву скажи и свечку поставь, тоже, говорят, помогает.
P>·>Причём тут текущее время? Проблема как раз была в том, что ты называешь "нефункциональные требования": "ну юзер же создался, а что ещё не совсем до конца создался, ничего страшного..".
P>Именно это нефункциональные требования и описывают — когда именно произойдет событие "юзер создался до конца". Вот здесь как правило запас по времени существенный.
P>Чем вы и пользуетесь для изменения дизайна
"Событие" — это функциональная сущность. Возврат результата из метода — это событие. Вначале у тебя событие означало "юзер создался до конца", а после того как ты переложил обработку в очередь, то смысл события поменялся на "создался, но не очеь". Это функциональное изменение.
P>>>Вот-вот. И если BA даёт добро — всё хорошо.
P>·>Ну вот это "добро" тебе и надо будет выразить в тестах.
P>Разумеется.
Т.е. без добра существующие тесты должны падать. ЧТД.
P>>>·>Из слов "паттерн тестируется" неясно кем.
P>>>Если руками, что следует из выделеного, то какие варианты?
P>·>Мде, отстой.
P>Расскажите, как лучше. Желательно на тех самых фильтрах — откуда возьмете первый вариант запроса к бд, орм, нужное-вписать, и как будете его тестировать
Напишу. Тестировать — тестами.
P>>>Я вам выделил, что бы виднее было.
P>·>Что за тест "против бд минимально заполненой под задачу"? Какие части системы он тестирует? e2e? или связка репо+бд? Или ещё что?
P>В зависимости от конкретного дизайна:
P>репозиторий + бд — если все запросы генерируются самим репозиторием
P>юз-кейс + репозиторий + бд — если у нас генерация выражений находится вне репозитория
Что именно ты не сможешь покрыть такими тестами, что тебе требуется побуквенно sql сравнивать?
P>>>Не работает — вы не знаете проблемной комбинации для фильтров. Знаете только что они есть и их хрензнаетсколькилион
P>·>Комбинация ровно та же — что и в твоём тесте. Тест почти такой же — только вместо деталей реализации ассертится поведение.
P>Что вы будете ассертить в поведении?
Что возвращается ровно столько записей сколько требуется.
P>>>Что бы исключить ту самую проблему в явном виде — потенциальная загрузка всего содержимого таблицы.
P>·>Эта проблема не исключается тестом, как бы тебе это ни хотелось.
P>И давно у вас пост-условие стало тестом ?
С тех пор как ты так написал. Ты тут предложил проблему "потенциальная загрузка всего содержимого таблицы" исключать тестом с паттерном. Какое ещё постусловие? Ты контекст потерял. Напоминаю:
·>Было показано deep.eq(..."some string"...), т.е. буквальное, посимвольное сравнение текста sql-запроса. Неясно где какой тут паттерн который ты "объясняешь", но код не показываешь.
проверка паттерна посимвольным сравнением
1. что делаем — сравниваем посимвольно, т.к. другого варианта нет — на одну задачу пилить ast на алгебраических типах данных это овердохрена
2. для чего делаем — что бы зафиксировать паттерн
P>>>Покрывается. Я ж вам показал. Только решение и покрытие это разные вещи. В данном случае решение — постусловие. А тестами фиксируем, что бы не убежало
P>·>Что значит "не убежало"?
P>Пришел некто резкий и дерзкий и фиксанул "тут всё просто, я быстро". На его тестовой бд записей 60 штук, мелочовочка. А на проде это десятки миллионов.
Твои тесты с паттернами дерзкого не остановят. Свечка и молитва — гораздо надёжнее твоих тестов! Рекомендую.
P>>>Покажите пример регрессии, которая не будет обнаружена этим тестом.
P>·>Ну загрузится пол таблицы.
P>Полтаблицы это 20 записей? Не понял, что за кейс такой.
У тебя же таблица это "это десятки миллионов".
>> Или банально твой .top(10) не появится для какой-то конкретной комбинации фильтров, т.к. для этой комбинации решили немного переписать кусочек кода и забыли засунуть .top(10).
P>Что значит не появится? Если это пост-условие,оно будет применено для всего выхлопа, а не для разных подветок в вычислениях.
Если это постусловие, то и такой тест и не нужен — он не может дать ничего полезного.
P>>>Необязательно. Если я руками пишу весь запрос — то будет в коде явно. но запрос может и билдер создать.
P>·>Магически что-ли? Билдер рандомно top(10) не вставит, будет некий кусок кода который его ставит.
P>Поскольку билдер сложный, то можно сказать, что да, магически — прямой связи входа и выхода вы на глазок не обнаружите. Потому и надо подстраховываться в тестах.
Это значит, что и тесты могут пропустить некий вход, для которого твой билдер пропустит твой top(10) на выходе.
P>>>Некоторые детали нужно фиксировать в тестах, что бы случайно залетевший дятел не разрушил цивилизацию.
P>·>Дятлы тесты тоже умеют редактировать.
P>Умеют — здесь только код-ревью может помочь. О чем я вам и говорю в который раз.
Так я об этом и говорю, что тесты в твоём виде бесполезны и даже вредны, т.к. код-ревью усложняют. Давай приведи пример целиком — код + твой тест с паттерном и я тебе тыкну пальчиком что на ревью может пойти не так. Это происходит потому, что код в тесте будет практически копипаст главного кода, значит ревьюверу вообще смысла на код теста смотреть нет, т.к. там тупо то же самое.
>> А с учётом того, что у тебя в тестах полный текст sql — то это будет простой copy-paste и вечнозелёный тест. А на ревью определить корректность sql на вид могут не только лишь все.
P>В данном случае и не нужно, что бы все могли определять корректность — код заведомо нетривиальный.
Не то что "не нужно", а просто невозможно. Тесты никакой ценности не дают, просто шоб-було, культ карго. Всё делаетя только под пристальным вниманием Верховного Программиста.
P>>>Решение — пост-условие. А вот тест который я показал, он всего то гарантирует сохранность этого пост-условия.
P>·>Не гарантирует.
P>Видите — снова без аргументов, голословно
Я рассказал о false positive/negative таких тестов в ответе Sinclair. Да и ты сам написал только что — нужен кто-то очень умный для проведения PR для гарантии сохранности пост-условия, а всё потому, что твои тесты ничего не дают.
P>>>Если вы не можете сделать этого руками, то ваши попытки выразить это в коде и генерации данных будут иметь ту же особенность.
P>·>Ты не понял. Я могу сделать это не руками, а кодом.
P>Для простых фильров это работает. Для сложных — проще найти решение напрямую, в бд, что бы представлять, куда всё двигать
Потому что у тебя беда с тестами и тестовым окружением. Я понимаю, все там были, мне тоже в юности было комфортнее лезть напрямую в прод и там тестить.
P>·>Это где ты говорил такое месяц назад? Цитату.
P>Вам не только я, но и Синклер это же сказал.
Цитату месячной давности в студию. Или не было.
P>>>Пост-условия похоже для вас пустой звук, вам это всё равно кажется тестом. Тест всего лишь гарантирует сохранность пост-условия
P>·>Не гарантирует.
P>У вас похоже тесты вообще ничего не гарантируют. Зачем же вы их пишете?
Как инструмент упрощения и ускорения процесса разработки и контроля качества. Чтобы вручную не возиться, чтобы в прод не лазить за каждым чихом, чтобы за минуты проводить acceptance, а не ждать часами после релиза репортов от юзеров.
P>>>И решения и у меня, и у вас, для подобных кейсов будут одни и те же.
P>·>Ну может быть колонок id несколько разных и иногда они совпадают... но не всегда.
P>каким образом в одной таблице users может быть несколько колонок id ? byId — это запрос к праймари кей. Ломается только если схема поломана.
externalId, internalId, globalId, replicationId и хз что. byId — ну может быть и праймари, очень частный скучный случай. А более весёлым будет если у тебя появится byId(List<int> ids) и будешь возвращать всю базу для пустого входного списка, для которого забудешь e2e тест написать.
P>>>Вы снова чего то фантазируете.
P>·>Что фантазирую? Это вроде ты предлагаешь в код вставлять top(10) и тестом "фиксировать".
P>Это же пост-условие.
Я имел в виду, что если реквест потенциально выдаёт слишком много записей, то тупо брать только первые 10 — это очень странное решение. По уму надо либо делать пейджинг, либо просто слать отказ в виде 4xx/5xx кода, но нужно дать понять клиенту, что в его запросе неожиданно много записей, а не просто 10. Так что такое постусловие это какой-то очень частный случай который, честно говоря, я нигде не видел, чтобы это считалось нормой молча обрезать данные.
P>>>Нет, не могут. Так, как это утверждает т. Райса — вы true от false отличить не сможете. Можете потренироваться — тестами обнаружить функцию, которая всегда возвращает true. Валяйте.
P>·>"всегда" — это уже нетривиальное свойство. Проверка тривиального свойства это по сути "выполнить код и поглядеть на результат", т.е. тест практически.
P>Ловко вы опровергли теорему Райса!
P>В т.Райса нетривиальное свойство означает, что есть функции, которые им обладают, а есть те, которые не обладают.
Не совсем. Тривиальным условием например будет "код анализируемой программы содержит инструкцию X".
P>·>Не понял. Да, эта функция возвращает true. Тестом будет "f=() -> true; assertTrue(f())".
P>Вот-вот. Опровержение теоремы Райса!
Нет. Опровержением будет, если я напишу алшгоритм который будет для любого данного f утверждать, что этот самый f всегда возвращает true (что по твоим заверениям твои тесты тестируют "мой тест гарантирует, что top(10) будет стоять для всех комбинаций фильтров"). А для
() -> true — данный конкретный случай, код известен полностью заранее и для него существует известный полный комплект входов/выходов.
P>>>Смотрите выше, текст выделен H1, как раз эту вашу способность и "демонстрирует"
P>·>Так ещё до того как ты это написал уже говорил, что _необходимость_ ручного тестирования — проблема. Не надо так делать и рассказал как избежать эту необходимость.
P>Ручное тестирование плохо не само по себе, а когда оно увеличивает время разработки
P>А когда сокращает — очень даже хорошо
Это сигнал, что автоматическое тестирование организовано плохо.
P>>>Хрупкий — это я вам сразу сказал.
P>
P>·>deep.eq по-другому тупо не умеет.
P>Я снова выделил, что бы вам виднее было. Посимвольно это потому, что у меня в конкретном случае нет ни json, ни orm, ни еще какого ast.
Какие другие случаи бывают и как будет выглядеть код?
P>deep.eq дает нам вполне годную структурную эквивалентность.
P>Если вы ей не умеете пользоваться — значит это не ваш вариант
Мы умеем ей не пользоваться.
P>>>Да то, что искать тестами проблемные комбинации вы вспотеете. Нужно искать решение вне тестов.
P>·>Ясен пень, тестами комбинации не ищутся, а тестируются. Анализируешь код, coverage report, логи, спеки и т.п., потом пишешь тест подозрительной комбинации и смотришь как себя система ведёт.
P>И так будете для каждой комбинации, да? Дадите шанс юзеру убиться об ваш билдер фильтров?
Зачем для каждой? Классифицируем, моделируем, алгоритмизируем, етс. Вон как у Sinclair оказалось, что функция-то линейная и никаких экспоненциальых переборов комбинаций и не требуется, покрывается полностью от силы десятком тестов.
P>·>А этот кто-то как будет, ногами что-ли?
P>·>Ок, допустим ногами. А какие в базе будут данные на которой этот чаи-гпт будет проверять свои запросы вножную? За 2025 год, правильно?
P>Жалко, что нет шрифта больше чем h1
Ты не ответил на вопрос "А какие в базе будут данные в момент ручной проверки"?
P>·>Потом система меняется и паттерн перестаёт функционировать проверенным вручную способом, а тестам — пофиг, они вечнозелёные.
P>А интеграционные тесты вы забыли, да?
Ты заявлял, что интеграционными тестами ты не проверяешь всё.
P>Мне что, каждую строчку теперь H1 выделять, что бы вам виднее было?
Нет, достаточно внятно излагать свои мысли и отвечать на вопросы которые я задаю.
P>>>С фильтрами комбинаций столько, что солнце погаснет раньше ваших тестов.
P>·>Даже если и так, то до e2e-комбинаций и жизни Вселенной не хватит уж точно.
P>В том то и дело — количество e2e никак не зависит от количества комбинаций в фильтрах.
Почему?
P>>>Проблема в том, что бы генерить данные, нужно знать комбинации которые будут проблемными.
P>·>Это же требуется и для того чтобы чтобы руками проверять запросы.
P>Похоже, пост-условия для вас пустой звук. Для моего варианта нужно проверить,
P>1 работает ли пост-условие
P>2 находится ли оно на своем месте
P>3 все ли ветки ифов получат его
Именно. И для этого нужно знать комбинации которые будут проблемными.