Здравствуйте, Буравчик, Вы писали:
P>>Разница в том, что именно будете мокать. Или низкоуровневые репозитории, или высокоуровневые абстракции.
Б>Какая-то вода. Почему ты называешь репозитории низкоуровневыми? Они вполне себе работают с объектами бизнес-логики, и достаточно высокоуровневые. Б>Разъясни, что ты называешь высокоуровневыми абстракциями.
Я вам уже приводил пример — вы его обсуждать не хотите, делаете вид, что сложно раскрывать подветки
Здравствуйте, Pauel, Вы писали:
P>>>Я вам привожу общеизвестный факт — моки всех сортов обладают таким вот свойством. И вы показали почему то именно такие тесты, смотрите сами, что пишете. P>·>Давай определимся. В том образцовом коде у Фаулера — моки есть? P>Тот образцовый код демонстрирует совсем другое
Школьное сочинение на тему "что хотел сказать автор".
P> — композицию функциями, это основное, ради чего его стоит смотреть.
Я не знаю на какой вопрос ты отвечал. Напомню вопрос: "моки есть?". Варианты ответа: "Да", "Нет".
P>>>И точно так же похрен на ваши классы и интерфейсы. Но вы их не стесняетесь использовать, а структурная эквивалентность это ужос-ужос. P>·>Так я это и говорю, похрен на эквивалентность, и на классы, интерфейсы тоже похрен. Важно чтобы код выражал ожидания пользователя, а не что =="select *". Пользователь может ожидать, что "для такого фильтра вернуть такой-то список штуковин". А у тебя "для такого фильтра верунть такой sql-код и использовать такие-то приватные методы". P>Похоже, объяснения Синклера и мои про data complexity вам не помогли. Нету у вас варианта покрыть фильтры тестами на данных. Ради каждого теста, условно, вам надо не 2-3 элемента забрасывать в БД, а кучу данных во все таблицы которые учавствуют прямо или косвенно. P>Отсюда ясно, что мелкие тесты фильтров вы будете гонять на бд близкой к боевой. Ну или игнорировать такую проблему делая вид что "и так сойдет"
Совершенно верно, именно эта альтернатива и имеет место быть. Я использую подход "гонять на бд близкой к боевой" (только не по количеству записей, а по качеству), а у вас подход "и так сойдет" + куча хрупких бесполезных тестов.
P>>>А ифы, циклы, классы, экземпляры зачем вашим пользователям? А что если понадобится поменять один класс-интерфейс на другой? P>·>Ровно та же проблема, если понадобится поменять твою структуру на другую. P>Вы снова игнорируете аргументы — глубина и частота правок зависят от количества зависимостей, которое у вас получается конским. У меня же простой маппер. Его править придется только в том случае, если поменяется БЛ. У вас — любое изменение дизайна, например, ради оптимизации.
Количество зависимостей зависит от сложности задачи, моки тут не при чём. Если у тебя простой маппер, то и у меня будет простой репо.
P>>>Впрочем, вы уже сами согласились, что изменения дизайна сначала ломают моки. P>·>Это ты опять что-то перефантазировал. P>Смотрите сами: P>
P>>Я вам сказал, что при переходе от одного дизайна к другому моки отваливаются. Если вы мокнули репозиторий в одном варианте, а в другом варианте репозиторий вызывается не там, не так, не тогда — всё, приплыли.
P>Голословно заявил, да.
Я согласился с тем, что ты это заявил, а не то, что я с этим заявлением согласился.
P>>>Я взял пример для иллюстрации подхода. В другом месте вместо sql будет json-like структура, которая отлично сравнивается и визуализируется — например, при запросах по http или orm. P>>>Вот сегодня сделал тож самое для запросов к http rpc сервису — параметры, retry, api-key, итд. Теперь в тестах сразу видно, что именно уходит на сервис. P>·>А толку? Ну уходит, а с чего ты решил, что сервис будет с этим ушедшим работать? Будешь тесты в проде гонять? P>1 Задача "работает ли сервис с тем и этим" решается интеграционными тестами.
В тривиальных случаях только. В реальных случаях нужны конформационные тесты.
P>2 Задача "создаём только такие запросы, которых понятны тому сервису. Это решается простыми дешовыми юнит-тестами.
Не решается, совершенно. Это может быть решено, только если есть некая формальная спека сервиса, совместимость с которой можно тестировать.
P>Это две разные задачи. Вторую можно игнорировать, переложить на интеграционные, если у вас один единственный вариант запроса. А если у вас сложное вычисление — то интеграционными вы вспотеете всё это тестировать. И моки вам точно так же не помогут.
Помогут совместно с конформационными тестами.
P>>>SQL потому, что фильтры сделаны именно так. P>·>Именно — и это отстой. Тестируете детали как сделано, что works as coded. P>Тестируется вычисление фильтров, которое довольно сложное.
Без тестирования того факта, что вычисленный фильтр, тот самый твой "pattern" — правильный — это бесполезно.
P>>>Соответственно, можно подкинуть дешовых тестов используя структурную эквивалентность. Соответсвенно, фиксируем тестами свои ожидания, что бы будущие изменения в коде не сломали всё подряд P>·>Это плохой критерий для выбора тестов. P>Вы так и не дали никакого адекватного решения для фильтров. Те примеры, что вы приводили именно для тестирования фильтров не годятся.
Я не понял в чём негодность.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
P>> — композицию функциями, это основное, ради чего его стоит смотреть. ·>Я не знаю на какой вопрос ты отвечал. Напомню вопрос: "моки есть?". Варианты ответа: "Да", "Нет".
Вы продолжаете играть в какие то игры, и задаёте много раз вопрос на который ответ даден несколько раз.
Есть у фаулера моки или нет — в данном примере он демонстрирует совсем другое!
P>>Отсюда ясно, что мелкие тесты фильтров вы будете гонять на бд близкоагй к боевой. Ну или игнорировать такую проблему делая вид что "и так сойдет" ·>Совершенно верно, именно эта альтернатива и имеет место быть. Я испоо льзую подход "гонять на бд близкой к боевой" (только не по количеству записей, а по качеству), а у вас подход "и так сойдет" + куча хрупких бесполезных тестов.
То есть, вы снова предлагаете бороться с data complexity посредством большого количества тестов на реальной бд.
Вы раз за разом повторяете свое предложение, но почему то возмущаетесь, когда я вам про это напоминаю.
P>>Вы снова игнорируете аргументы — глубина и частота правок зависят от количества зависимостей, которое у вас получается конским. У меня же простой маппер. Его править придется только в том случае, если поменяется БЛ. У вас — любое изменение дизайна, например, ради оптимизации. ·>Количество зависимостей зависит от сложности задачи, моки тут не при чём. Если у тебя простой маппер, то и у меня будет простой репо.
Маппер тестируется простыми юнит-тестами. А ваш репозиторий, с ваших слов, надо "гонять на бд близкой к боевой"
И теперь остаётся надеяться на квалификацию того, кто бдет запорлнять эту бд — человечески фактор.
P>>
P>>>Я вам сказал, что при переходе от одного дизайна к другому моки отваливаются. Если вы мокнули репозиторий в одном варианте, а в другом варианте репозиторий вызывается не там, не так, не тогда — всё, приплыли.
P>>Голословно заявил, да.
·>Я согласился с тем, что ты это заявил, а не то, что я с этим заявлением согласился
Итого — вы тестируете контролер, который вызывает репозиторий. Мок нужен? Нужен.
Второй вариант, после оптимизации, вам приходится сначала писать в очередь, а сам репозиторий будет вызван другим процессом/сервисом при чтении из очереди.
Функциональных изменений нет.
Теперь заглядываем в ваши тесты контроллера, и видим:
Самое забавное, вы продолжаете с этим несоглашаться
P>>1 Задача "работает ли сервис с тем и этим" решается интеграционными тестами. ·>В тривиальных случаях только. В реальных случаях нужны конформационные тесты.
Это разновидность интеграционных. Вы снова играете в слова.
P>>2 Задача "создаём только такие запросы, которых понятны тому сервису. Это решается простыми дешовыми юнит-тестами. ·>Не решается, совершенно. Это может быть решено, только если есть некая формальная спека сервиса, совместимость с которой можно тестировать.
Вы ухитряетесь противоречить себе же в одном абзаце. Репозиторий вы гоняете на боевой бд. А вызов другого сервиса будете тестировать на боевом сервисе?
У вас здесь ровно та же data complexity.
Например, мы можем проверить, что делаем правильный энкодинг, правильную склейку, правильный маппинг, правильный эскейпинг, итд и тд.
P>>Это две разные задачи. Вторую можно игнорировать, переложить на интеграционные, если у вас один единственный вариант запроса. А если у вас сложное вычисление — то интеграционными вы вспотеете всё это тестировать. И моки вам точно так же не помогут. ·>Помогут совместно с конформационными тестами.
Подробнее — как вам моки помогут гарантировать, что всё многообразие символов вы энкодите согласно протоколу?
P>>Тестируется вычисление фильтров, которое довольно сложное. ·>Без тестирования того факта, что вычисленный фильтр, тот самый твой "pattern" — правильный — это бесполезно.
С этим никто и не спорит!!! Вы хоть читаете?
1) Рабочий паттерн или нет — это проверяется на бд, в идеале, той, что содержит реальные данные. А они могут появиться только после релиза в следующем году?
Вы что, пойдете к менеджеру и скажете "нет боевой базы" я запрос через год напишу?
2) При этом для реализации фильтра вам нужно понимать, что возможные параметры будут давать рабочие паттерны.
Тестов только для 1) недостаточно, т.к. например ваш маппер рендерит 'test1 test2' вместо 'test1','test2'. Такое вы проверите только на тех наборах данных, где есть пробел.
А если вдруг нужно энкодить всё многообразие спецсимволов, юникод строк
А потом может оказаться так, что некоторые параметры надо энкодить так, другие — эдак, один и тот же параметр в зависимости от места применения должен кодироваться то так, то эдак.
И всё это вы собираетесь "гонять на бд близкой к боевой"
P>>Вы так и не дали никакого адекватного решения для фильтров. Те примеры, что вы приводили именно для тестирования фильтров не годятся. ·>Я не понял в чём негодность.
В том, что в фильтр приходит конское количество данных самых разных типов, а на выходе должны быть только рабочие паттерны
Здравствуйте, Pauel, Вы писали:
P>>> — композицию функциями, это основное, ради чего его стоит смотреть. P>·>Я не знаю на какой вопрос ты отвечал. Напомню вопрос: "моки есть?". Варианты ответа: "Да", "Нет". P>Вы продолжаете играть в какие то игры, и задаёте много раз вопрос на который ответ даден несколько раз.
Так "да" или "нет"?
P>Есть у фаулера моки или нет — в данном примере он демонстрирует совсем другое!
Это твои личные заморочки что конкретно _ты_ увидел в этой демонстрации. Суть в том, что даже в таком тривиальном примере мок есть и это факт, а факт вещь упрямая. Если ты считаешь, что можно по-другому — весь код у тебя есть, форкни, сделай всё как считаешь должным.
P>·>Совершенно верно, именно эта альтернатива и имеет место быть. Я испоо льзую подход "гонять на бд близкой к боевой" (только не по количеству записей, а по качеству), а у вас подход "и так сойдет" + куча хрупких бесполезных тестов. P>То есть, вы снова предлагаете бороться с data complexity посредством большого количества тестов на реальной бд.
Нет, такое я не предгалаю.
P>Вы раз за разом повторяете свое предложение, но почему то возмущаетесь, когда я вам про это напоминаю.
Это твои фантазии.
P>·>Количество зависимостей зависит от сложности задачи, моки тут не при чём. Если у тебя простой маппер, то и у меня будет простой репо. P>Маппер тестируется простыми юнит-тестами. А ваш репозиторий, с ваших слов, надо "гонять на бд близкой к боевой" P>И теперь остаётся надеяться на квалификацию того, кто бдет запорлнять эту бд — человечески фактор.
Я на это уже отвечал.
P>·>Я согласился с тем, что ты это заявил, а не то, что я с этим заявлением согласился P>Итого — вы тестируете контролер, который вызывает репозиторий. Мок нужен? Нужен.
Он нужен не потому, что я тестирую контроллер, а потому что я отрезаю медленный и неуклюжий, но простой переситсенс от быстрой, но сложной бизнес-логики.
P>Второй вариант, после оптимизации, вам приходится сначала писать в очередь, а сам репозиторий будет вызван другим процессом/сервисом при чтении из очереди. P>Функциональных изменений нет.
Есть, конечно. Например, изменяется транзакционность, согласованность, &c. Ты это даже не понимаешь, что это именно функциональность. Отсюда у тебя потом ВНЕЗАПНО возникают чудесные вещи типа "после того, как сделал var u = service.CreateUser(...), нужно выждать не менее 5 минут перед service.UpdateUser(u, ...)".
get-return это запрос-ответ. Неясно как это можно переписать на очередь без значительного изменения функциональности.
P>>>1 Задача "работает ли сервис с тем и этим" решается интеграционными тестами. P>·>В тривиальных случаях только. В реальных случаях нужны конформационные тесты. P>Это разновидность интеграционных. Вы снова играете в слова.
Да у тебя всё разновидность интеграционных. Конформационные тесты подразумевают, что внешний сервис тестируется отдельно от проекта. И проект отдельно тестируется с моками внешнего сервиса. Что с чем тут интегриуется — я не могу представить, моя фантазия не настолько безграничная.
P>·>Не решается, совершенно. Это может быть решено, только если есть некая формальная спека сервиса, совместимость с которой можно тестировать. P>Вы ухитряетесь противоречить себе же в одном абзаце. Репозиторий вы гоняете на боевой бд.
Это ты опять врёшь, надеюсь, что хоть чуточку краснея.
P> А вызов другого сервиса будете тестировать на боевом сервисе?
Нет. Я же написал как. Несколько раз.
P>У вас здесь ровно та же data complexity. P>Например, мы можем проверить, что делаем правильный энкодинг, правильную склейку, правильный маппинг, правильный эскейпинг, итд и тд.
Не можете. Такими тестами вы можете проверить, что текст запроса равен select *...., но не можете проверить, что он правильный. Правильность текста запроса будут проверять только ваши юзеры в проде, т.к. и интеграционными тестами не можете покрыть каждый запрос, ибо data complexity для тестов проекта в сборе выше, чем в тестах реп.
P>>>Это две разные задачи. Вторую можно игнорировать, переложить на интеграционные, если у вас один единственный вариант запроса. А если у вас сложное вычисление — то интеграционными вы вспотеете всё это тестировать. И моки вам точно так же не помогут. P>·>Помогут совместно с конформационными тестами. P>Подробнее — как вам моки помогут гарантировать, что всё многообразие символов вы энкодите согласно протоколу?
"согласно протоколу" — это и есть конформационные тесты, по определению. Моки же позволяют не маяться дурью гарантирования энкодинга в тестах вашей бизнес-логики.
P>·>Без тестирования того факта, что вычисленный фильтр, тот самый твой "pattern" — правильный — это бесполезно. P>С этим никто и не спорит!!! Вы хоть читаете? P>1) Рабочий паттерн или нет — это проверяется на бд, в идеале, той, что содержит реальные данные. А они могут появиться только после релиза в следующем году? P>Вы что, пойдете к менеджеру и скажете "нет боевой базы" я запрос через год напишу?
Т.е. ты не можешь написать тест т.к. для проверки паттерна у тебя ещё нет реальных данных? Совершенно верно. И это плохо. Не надо так делать.
P>2) При этом для реализации фильтра вам нужно понимать, что возможные параметры будут давать рабочие паттерны. P>Тестов только для 1) недостаточно, т.к. например ваш маппер рендерит 'test1 test2' вместо 'test1','test2'. Такое вы проверите только на тех наборах данных, где есть пробел. P>А если вдруг нужно энкодить всё многообразие спецсимволов, юникод строк P>А потом может оказаться так, что некоторые параметры надо энкодить так, другие — эдак, один и тот же параметр в зависимости от места применения должен кодироваться то так, то эдак. P>И всё это вы собираетесь "гонять на бд близкой к боевой"
И? Предлагаешь это не тестировать вообще? По факту ты просто загоняешь свои assumptions что надо "так, а не эдак" в свой pattern и оставляешь это вообще не покрытым вообще никак. Поэтому и необходимы конф-тесты вида, что repo.save(...."многообразие спецсимволов"); assertThat(repo.load(....)).isGood() на системе близкой к боевой, а не просто так как тебе кажется должно быть. Имея такие тесты можно уже спокойно тестировать свою бизнес-логику моками вида verify(repo).save(...."simple value") зная, что энкодинг спецсиволов уже проверен конф-тестами.
P>·>Я не понял в чём негодность. P>В том, что в фильтр приходит конское количество данных самых разных типов, а на выходе должны быть только рабочие паттерны
Ты всё ещё скрываешь как же ты ассертишь рабочесть паттернов. Кода я, конечно, не увижу, т.к. это делаешь на честном слове, вручную, если не забыл.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
P>>Есть у фаулера моки или нет — в данном примере он демонстрирует совсем другое! ·>Это твои личные заморочки что конкретно _ты_ увидел в этой демонстрации.
Даем слово Фаулеру, again
By choosing to fulfill dependency contracts with functions rather than classes, minimizing the code sharing between modules and driving the design through tests, I can create a system composed of highly discrete, evolvable, but still type-safe modules
Фаулер пишет, что он взял функции вместо классов. Это и есть его цель. А вы думаете, что он показывал, будто без моков нельзя
> Суть в том, что даже в таком тривиальном примере мок есть и это факт, а факт вещь упрямая.
Что раз Фаулер так делает, то иначе ну никак нельзя? Моки можно всунуть куда угодно, хоть для теста синусов и косинусов, — это ничего не говорит.
P>>·>Совершенно верно, именно эта альтернатива и имеет место быть. Я испоо льзую подход "гонять на бд близкой к боевой" (только не по количеству записей, а по качеству), а у вас подход "и так сойдет" + куча хрупких бесполезных тестов. P>>То есть, вы снова предлагаете бороться с data complexity посредством большого количества тестов на реальной бд. ·>Нет, такое я не предгалаю.
Именно это вы и говорите. Ну, как вариант, не читаете.
Речь именно про фильтры. Смотрите сами:
Отсюда ясно, что мелкие тесты фильтров вы будете гонять на бд близкоагй к боевой. Ну или игнорировать такую проблему делая вид что "и так сойдет"
·>Совершенно верно, именно эта альтернатива и имеет место быть. Я испоо льзую подход "гонять на бд близкой к боевой"
И вы предлагаете вместо этих тестов гонять всё через бд. Откуда ясно, что 1 время прогона увеличивается на порядки, 2 боевых данных у вас нет — пойдете к менедеджеру "Вася, я тесты в следуюем году подкину"
P>>Итого — вы тестируете контролер, который вызывает репозиторий. Мок нужен? Нужен. ·>Он нужен не потому, что я тестирую контроллер, а потому что я отрезаю медленный и неуклюжий, но простой переситсенс от быстрой, но сложной бизнес-логики.
Сейчас важно, что он нужен.
P>>Второй вариант, после оптимизации, вам приходится сначала писать в очередь, а сам репозиторий будет вызван другим процессом/сервисом при чтении из очереди. P>>Функциональных изменений нет. ·>Есть, конечно. Например, изменяется транзакционность, согласованность, &c. Ты это даже не понимаешь, что это именно функциональность.
Согласованность, транзакционность, задержка — это всё НЕФУНКЦИОНАЛЬНЫЕ.
Т.е., условно, вы выяснили, что не успеваете, опаньки! И надо выталкивать процессинг в очередь. Упс — написали тесты, покрыли моками, выбросили моки, переписали тесты, но уже на других моках, ой...
·>
·>get-return это запрос-ответ. Неясно как это можно переписать на очередь без значительного изменения функциональности.
Вам сюда: https://en.wikipedia.org/wiki/Non-functional_requirement
P>>Это разновидность интеграционных. Вы снова играете в слова. ·>Да у тебя всё разновидность интеграционных. Конформационные тесты подразумевают, что внешний сервис тестируется отдельно от проекта. И проект отдельно тестируется с моками внешнего сервиса. Что с чем тут интегриуется — я не могу представить, моя фантазия не настолько безграничная.
Интеграция начинается с момента, когда одна ваша функция вызывает другую вашу функцию. Конформационный тест требует запуска приложения или подсистемы, что автоматически означает интеграционный уровень.
Правильно понимаю, вы собираетесь тестировать эскейпинг каких кавычек, собирая приложение и запуская его против мока внешнего сервиса?
Весело у вас там.
P>>Вы ухитряетесь противоречить себе же в одном абзаце. Репозиторий вы гоняете на боевой бд. ·>Это ты опять врёшь, надеюсь, что хоть чуточку краснея.
Вот ваши слова про репозиторий "гонять на бд близкой к боевой"
Так и вижу — тесты на эскейпинг символов прогонять на клоне прода. Собственно, это и есть ваша идея применения конформационных тестов.
P>>Например, мы можем проверить, что делаем правильный энкодинг, правильную склейку, правильный маппинг, правильный эскейпинг, итд и тд. ·>Не можете. Такими тестами вы можете проверить, что текст запроса равен select *...., но не можете проверить, что он правильный. Правильность текста запроса будут проверять только ваши юзеры в проде, т.к. и интеграционными тестами не можете покрыть каждый запрос, ибо data complexity для тестов проекта в сборе выше, чем в тестах реп.
В который раз объясняю. Нам нужны 2 условия(ДВА!)
1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
2. рабочая схема построения такого паттерна
1 — необходимое условие
1 + 2 необходимое и достаточное
Почему недостаточно п1
— сервис или бд или сторадж требует эспейпить, энкодить, инлайнить, склеивать, подставлять итд и тд
— маппер параметр->значение это целая куча кейсов, много больше, чем вы можете себе позволить методом "гонять на бд близкой к боевой"
P>>Подробнее — как вам моки помогут гарантировать, что всё многообразие символов вы энкодите согласно протоколу? ·>"согласно протоколу" — это и есть конформационные тесты, по определению. Моки же позволяют не маяться дурью гарантирования энкодинга в тестах вашей бизнес-логики.
Вы реализацию хоть какого клиентского протокола видели когда нибудь? Там сотни и тысячи тестов покрывают кейсы вида '$var- заменяем на значение var с удалением всех пробельных символов после нее'
Фильтр который вы пишете, это ровно такой же специализированый клиент. И тут, о чудо, можно обходиться без всех таких кейсов
P>>Вы что, пойдете к менеджеру и скажете "нет боевой базы" я запрос через год напишу? ·>Т.е. ты не можешь написать тест т.к. для проверки паттерна у тебя ещё нет реальных данных? Совершенно верно. И это плохо. Не надо так делать.
Где взять боевые данные за февраль 2025го? Вы в курсе, что сейчас 2024й год ?
P>>А потом может оказаться так, что некоторые параметры надо энкодить так, другие — эдак, один и тот же параметр в зависимости от места применения должен кодироваться то так, то эдак. P>>И всё это вы собираетесь "гонять на бд близкой к боевой" ·>И? Предлагаешь это не тестировать вообще?
Я уже третий месяц рассказываю как именно это нужно тестировать.
>По факту ты просто загоняешь свои assumptions что надо "так, а не эдак" в свой pattern и оставляешь это вообще не покрытым вообще никак.
Работает ли паттерн корретно, и строится ли он корректно — это два множества вариантов которые всего лишь пересекаются.
> зная, что энкодинг спецсиволов уже проверен конф-тестами.
Я так и думал — вы будете собирать пол-приложения что бы погонять против внешнего сервиса на предмет "заэскейпили кавычку"
P>>В том, что в фильтр приходит конское количество данных самых разных типов, а на выходе должны быть только рабочие паттерны ·>Ты всё ещё скрываешь как же ты ассертишь рабочесть паттернов. Кода я, конечно, не увижу, т.к. это делаешь на честном слове, вручную, если не забыл.
Я ж вам сказал — рабочий паттерн или нет, это проверяем до того, как начнем код коммитить, руками на бд. Интеграционные тесты проверяют его еще раз, на бд.
А дальше нужно покрыть тестами всю мелочевку — построение запроса таким образом, что бы получался рабочий паттерн
P>·>Так "да" или "нет"?
Т.е. прямой вопрос ты опять игнорируешь и продолжаешь лить воду.
P>Фаулер пишет, что он взял функции вместо классов. Это и есть его цель. А вы думаете, что он показывал, будто без моков нельзя
Ещё бы, ведь в js тупо нет классов. Да и похрен, к обсуждаемой теме это не относится. К обсуждению отностится твои заявления о том, что функции и вообще весь такой современный правильный дизайн без классов как-то избавляет от моков. Мой поинт в том, что моки это не про то как пишется код, функциями, классами или чёртом лысым, а про внешние зависимости. И никакой правильный дизайн от них не избавляет, т.к. зависимости диктуются требованиями, а не дизайном. Если у тебя есть субд, будут моки, как ни дизайни. Ну или если у тебя хоумпейдж, а там что угодно делай, не важно.
>> Суть в том, что даже в таком тривиальном примере мок есть и это факт, а факт вещь упрямая. P>Что раз Фаулер так делает, то иначе ну никак нельзя?
Нельзя. И ты ещё не показал, что можно. Код у тебя весь есть, сделай форк и вперёд, а я [willy-wonka-meme.gif].
P>Моки можно всунуть куда угодно, хоть для теста синусов и косинусов, — это ничего не говорит.
Ты говорил, что моки и это всё — это старьё из 00х. Как оказалось — и тут ты налажал, т.к. статья 2023 года имеет те же самые "устаревшие" моки.
P>>>То есть, вы снова предлагаете бороться с data complexity посредством большого количества тестов на реальной бд. P>·>Нет, такое я не предгалаю. P>Именно это вы и говорите. Ну, как вариант, не читаете.
Ты нафантазировал "на реальной бд", а я писал "на бд близкой к боевой (только не по количеству записей, а по качеству)". Разницу не видишь, да?
P>И вы предлагаете вместо этих тестов гонять всё через бд. Откуда ясно, что 1 время прогона увеличивается на порядки, 2 боевых данных у вас нет — пойдете к менедеджеру "Вася, я тесты в следуюем году подкину"
Это опять твои фантазии из неумения читать, что тебе пишут.
P>>>Итого — вы тестируете контролер, который вызывает репозиторий. Мок нужен? Нужен. P>·>Он нужен не потому, что я тестирую контроллер, а потому что я отрезаю медленный и неуклюжий, но простой переситсенс от быстрой, но сложной бизнес-логики. P>Сейчас важно, что он нужен.
Потому что он необходим.
P>·>Есть, конечно. Например, изменяется транзакционность, согласованность, &c. Ты это даже не понимаешь, что это именно функциональность. P> Согласованность, транзакционность, задержка — это всё НЕФУНКЦИОНАЛЬНЫЕ.
Как это? Возможность поизменять пользователя после его создания — это функциональное требование.
P>Т.е., условно, вы выяснили, что не успеваете, опаньки! И надо выталкивать процессинг в очередь. Упс — написали тесты, покрыли моками, выбросили моки, переписали тесты, но уже на других моках, ой...
Это требует согласования с бизнесом, а не просто так, чтобы не было тех чудес как у тебя бывает.
P>·>Да у тебя всё разновидность интеграционных. Конформационные тесты подразумевают, что внешний сервис тестируется отдельно от проекта. И проект отдельно тестируется с моками внешнего сервиса. Что с чем тут интегриуется — я не могу представить, моя фантазия не настолько безграничная. P>Интеграция начинается с момента, когда одна ваша функция вызывает другую вашу функцию. Конформационный тест требует запуска приложения или подсистемы, что автоматически означает интеграционный уровень.
Нет, конформационный тест не требует запуска приложения или системы. Читай мою переписку с Sinclair.
P>Правильно понимаю, вы собираетесь тестировать эскейпинг каких кавычек, собирая приложение и запуская его против мока внешнего сервиса?
Нет, не правильно понимаешь.
P>>>Вы ухитряетесь противоречить себе же в одном абзаце. Репозиторий вы гоняете на боевой бд. P>·>Это ты опять врёшь, надеюсь, что хоть чуточку краснея. P>Вот ваши слова про репозиторий "гонять на бд близкой к боевой" P>Так и вижу — тесты на эскейпинг символов прогонять на клоне прода. Собственно, это и есть ваша идея применения конформационных тестов.
Бредишь.
P>>>Например, мы можем проверить, что делаем правильный энкодинг, правильную склейку, правильный маппинг, правильный эскейпинг, итд и тд. P>·>Не можете. Такими тестами вы можете проверить, что текст запроса равен select *...., но не можете проверить, что он правильный. Правильность текста запроса будут проверять только ваши юзеры в проде, т.к. и интеграционными тестами не можете покрыть каждый запрос, ибо data complexity для тестов проекта в сборе выше, чем в тестах реп. P>В который раз объясняю. Нам нужны 2 условия(ДВА!) P>1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу P>2. рабочая схема построения такого паттерна P>1 — необходимое условие P>1 + 2 необходимое и достаточное
Я не знаю что ты в этом месте понимаешь под "паттерн", но я всегда имел в виду твой конкретный "const pattern =" вот тут
. Такой паттерн вручную прповерять — большая беда, надо тестировать с бд автоматически.
P>Почему недостаточно п1 P>- сервис или бд или сторадж требует эспейпить, энкодить, инлайнить, склеивать, подставлять итд и тд
Так это сервис требует, а не твоя бизнес-логика, это и будет конф-тест тестировать.
P>- маппер параметр->значение это целая куча кейсов, много больше, чем вы можете себе позволить методом "гонять на бд близкой к боевой"
Но эти кейсы плотно связаны с тем как выглядит реальный recordset. Например, о том как субд превращает null в default value я тебе уже рассказал. И в твоём подходе это остаётся непокрытым.
P>>>Подробнее — как вам моки помогут гарантировать, что всё многообразие символов вы энкодите согласно протоколу? P>·>"согласно протоколу" — это и есть конформационные тесты, по определению. Моки же позволяют не маяться дурью гарантирования энкодинга в тестах вашей бизнес-логики. P>Вы реализацию хоть какого клиентского протокола видели когда нибудь? Там сотни и тысячи тестов покрывают кейсы вида '$var- заменяем на значение var с удалением всех пробельных символов после нее' P>Фильтр который вы пишете, это ровно такой же специализированый клиент. И тут, о чудо, можно обходиться без всех таких кейсов
Это будет код и тесты клиента для протокола, а не код бизнес-логики твеого приложения, которое этого клиента использует.
P>>>Вы что, пойдете к менеджеру и скажете "нет боевой базы" я запрос через год напишу? P>·>Т.е. ты не можешь написать тест т.к. для проверки паттерна у тебя ещё нет реальных данных? Совершенно верно. И это плохо. Не надо так делать. P>Где взять боевые данные за февраль 2025го? Вы в курсе, что сейчас 2024й год ?
Не знаю, ты рассказывай, ведь тебе требуется "Рабочий паттерн или нет — это проверяется на бд, в идеале, той, что содержит реальные данные". Рассказывай где-ты берёшь реальные данные за 2025 год для проверки работосбособности твоих паттернов.
P>·>И? Предлагаешь это не тестировать вообще? P>Я уже третий месяц рассказываю как именно это нужно тестировать.
Меня ответы "никак", "руками", "используя реальные данные за 2025 год" не устраивают. А с другими ответами ты не соглашаешься.
>>По факту ты просто загоняешь свои assumptions что надо "так, а не эдак" в свой pattern и оставляешь это вообще не покрытым вообще никак. P>Работает ли паттерн корретно, и строится ли он корректно — это два множества вариантов которые всего лишь пересекаются.
Почему пересекаются? Каким образом некорректно построенный паттерн может работать корректно? Раз работает, значит построен.
Разница значительна: "Работает ли" — важно и нужно тестировать, инвариант диктуемый бизнесом, "строится ли" — это мелкие детали имплементации, которые меняются постоянно.
>> зная, что энкодинг спецсиволов уже проверен конф-тестами. P>Я так и думал — вы будете собирать пол-приложения что бы погонять против внешнего сервиса на предмет "заэскейпили кавычку"
Я знаю что ты так думал, осталось тебе перестать так думать.
P>>>В том, что в фильтр приходит конское количество данных самых разных типов, а на выходе должны быть только рабочие паттерны P>·>Ты всё ещё скрываешь как же ты ассертишь рабочесть паттернов. Кода я, конечно, не увижу, т.к. это делаешь на честном слове, вручную, если не забыл. P>Я ж вам сказал — рабочий паттерн или нет, это проверяем до того, как начнем код коммитить, руками на бд.
P>Интеграционные тесты проверяют его еще раз, на бд.
В на прод-бд с данными за 2025 год. Я правильно понял?
P>А дальше нужно покрыть тестами всю мелочевку — построение запроса таким образом, что бы получался рабочий паттерн
Отстой.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
P>>·>Так "да" или "нет"? ·>Т.е. прямой вопрос ты опять игнорируешь и продолжаешь лить воду.
Зачем? Прямой ответ уже был даден. Раз вы продолжаете вопрошать, значит вам точно надо чтото другое. Играйте в свои игры без меня.
P>>Фаулер пишет, что он взял функции вместо классов. Это и есть его цель. А вы думаете, что он показывал, будто без моков нельзя ·>Ещё бы, ведь в js тупо нет классов.
Одно из двух — вы пользуетесь Internet Explorer или у вас апдейты Лялиха поломались еще в нулевых.
>Мой поинт в том, что моки это не про то как пишется код, функциями, классами или чёртом лысым, а про внешние зависимости. И никакой правильный дизайн от них не избавляет, т.к. зависимости диктуются требованиями, а не дизайном. Если у тебя есть субд, будут моки, как ни дизайни. Ну или если у тебя хоумпейдж, а там что угодно делай, не важно.
Зависимости — требованиями, а способ их протаскивания — дизайном. Соответственно, моки это обрезание тех зависимостей, которые вы же сами затолкали куда поглубже, да еще неглядя.
P>>Что раз Фаулер так делает, то иначе ну никак нельзя? ·>Нельзя. И ты ещё не показал, что можно.
Серьёзная логика. А еще Фаулер показал олдскульный жээс и вдвое большее количество кода, чем нужно, даже с его подходом.
Полагаю, вы щас начнете удваивать количество кода и возвращаться на 8ю джаву?
P>>Моки можно всунуть куда угодно, хоть для теста синусов и косинусов, — это ничего не говорит. ·>Ты говорил, что моки и это всё — это старьё из 00х. Как оказалось — и тут ты налажал, т.к. статья 2023 года имеет те же самые "устаревшие" моки.
Статья совсем про другое, о чем сам же Фаулер и пишет — про композицию функций. А вы там только моки видите.
P>>Именно это вы и говорите. Ну, как вариант, не читаете. ·>Ты нафантазировал "на реальной бд", а я писал "на бд близкой к боевой (только не по количеству записей, а по качеству)". Разницу не видишь, да?
Небольшая разница — Data complexity говорит о том, что вам не покрыть и ничтожной части вариантов вашими тестами.
P>>·>Есть, конечно. Например, изменяется транзакционность, согласованность, &c. Ты это даже не понимаешь, что это именно функциональность. P>> Согласованность, транзакционность, задержка — это всё НЕФУНКЦИОНАЛЬНЫЕ. ·>Как это? Возможность поизменять пользователя после его создания — это функциональное требование.
А так — в контроллере останется ровно то, что требуется для функциональных требований. А вот всё остальное вам придется распихивать, например, в ту же очередь. И вот такие изменения ломают и ваши моки, и тесты на них.
P>>Т.е., условно, вы выяснили, что не успеваете, опаньки! И надо выталкивать процессинг в очередь. Упс — написали тесты, покрыли моками, выбросили моки, переписали тесты, но уже на других моках, ой... ·>Это требует согласования с бизнесом, а не просто так, чтобы не было тех чудес как у тебя бывает.
Я так вижу, бизнес вам имена классов и названия методов диктует, да еще 100500 готовых тестов подкидывает.
P>>Интеграция начинается с момента, когда одна ваша функция вызывает другую вашу функцию. Конформационный тест требует запуска приложения или подсистемы, что автоматически означает интеграционный уровень. ·>Нет, конформационный тест не требует запуска приложения или системы. Читай мою переписку с Sinclair.
Вы наверное подумали, но забыли написать. Поиск по треду никаких пояснений, как вы используете конформационные тесты, не дал.
Могу рассказать, как это делается при реализации клиента под протокол — у вас есть 100500 эталонов на все случаи жизни, которые должен проглотить ваш клиент.
Ровно так же поступают и с компилятором — запускают и прогоняют 100500 примеров кода по спецификации.
Если вы сами пишете фильтры — а именно такую задачу я вам предложил, то это ваша ответсвенность учесть все возможные кейсы того, как хранятся и кодируются данные в бд — имена колонок, таблиц, строк, подстрок, кусков json, итд итд.
Фактически, вы пишете ни больше, ни меньше, а небольшой компилятор из json в sql. Только у вас нет этих самых эталонов — под вашу бд и придумки их никто не заготовил.
P>>В который раз объясняю. Нам нужны 2 условия(ДВА!) P>>1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу P>>2. рабочая схема построения такого паттерна P>>1 — необходимое условие P>>1 + 2 необходимое и достаточное ·>Я не знаю что ты в этом месте понимаешь под "паттерн", но я всегда имел в виду твой конкретный "const pattern =" вот тут
. Такой паттерн вручную прповерять — большая беда, надо тестировать с бд автоматически.
Похоже, вы что Фаулера, что меня, понимаете както слишком буквально. Я вам показал перевод из рабочего в минимально понятный здесь, вне контекста.
1. получили рабочий паттерн
2. строим маппер вокруг этого паттерна
п1 — паттерн тестируется на бд, далее — интеграционными тестами
п2 — построение запроса тестируется как все мапперы, без исключения
Без п2 вы спокойно напоретесь на кейс с уязвимостью, или поломкой на энкодинге данных, или с (не)подтягиванием данных из (не)тех таблиц
P>>- сервис или бд или сторадж требует эспейпить, энкодить, инлайнить, склеивать, подставлять итд и тд ·>Так это сервис требует, а не твоя бизнес-логика, это и будет конф-тест тестировать.
Подробнее — кто и где выдаст вам конф-тест, что запросы смогут внятн что работать с такими вещами — email в таблице users это сам емейл строкой, а email в таблице reply будет mailto:<email>, а в customer он будет в колонке типа json с названием поля 'details' который есть список имя-значение.
P>>Фильтр который вы пишете, это ровно такой же специализированый клиент. И тут, о чудо, можно обходиться без всех таких кейсов ·>Это будет код и тесты клиента для протокола, а не код бизнес-логики твеого приложения, которое этого клиента использует.
А разница то какая? Вы одну часть тестов назвали другим именем, от этого сложность поменялась?
P>>Где взять боевые данные за февраль 2025го? Вы в курсе, что сейчас 2024й год ? ·>Не знаю, ты рассказывай, ведь тебе требуется "Рабочий паттерн или нет — это проверяется на бд, в идеале, той, что содержит реальные данные". Рассказывай где-ты берёшь реальные данные за 2025 год для проверки работосбособности твоих паттернов.
Мне нужно всего лишь паттерн проверить, а не конечный запрос, как у вас. Потому мне в будущее заглядывать не надо, цитирую себя "тестом бд минимально заполненой под задачу"
P>>Я уже третий месяц рассказываю как именно это нужно тестировать. ·>Меня ответы "никак", "руками", "используя реальные данные за 2025 год" не устраивают. А с другими ответами ты не соглашаешься.
Смотрите внимательно — объяснение ниже я вам приводил уже около десятка раз
В который раз объясняю. Нам нужны 2 условия(ДВА!)
1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
2. рабочая схема построения такого паттерна
1 — необходимое условие
1 + 2 необходимое и достаточное
P>>Работает ли паттерн корретно, и строится ли он корректно — это два множества вариантов которые всего лишь пересекаются. ·>Почему пересекаются? Каким образом некорректно построенный паттерн может работать корректно? Раз работает, значит построен.
Вот-вот. Вы здесь снова пишете, что не в курсе data complexity и объяснения Sinclair прошли мимо, и понимать это не хотите
·>Разница значительна: "Работает ли" — важно и нужно тестировать, инвариант диктуемый бизнесом, "строится ли" — это мелкие детали имплементации, которые меняются постоянно.
Вы что, не помните как в школе на математике или физике подгоняли решение под ответ? Правильный паттерн, некорректно построен, ответ верный — "Молодец, садись, два балла!".
Почему некорретно построеный паттерн дает корректный результат:
1. у вас нет данных на год вперёд, и половина базы вообще пустая.
2. у вас в бд только 1% частных случаев
3. вы думаете, что бд у вас заполнена верно, но реально это не так.
4. у вас в базе много данных, которые похожи друг на друга
Т.е. это те самые ошибки которые вы на тестах бд не увидите. Но они видны при построении запроса.
P>>А дальше нужно покрыть тестами всю мелочевку — построение запроса таким образом, что бы получался рабочий паттерн ·>Отстой.
Ну да, Фаулер пока не написал такую статью. Ждите еще 20 лет
Здравствуйте, Pauel, Вы писали:
P>·>Т.е. прямой вопрос ты опять игнорируешь и продолжаешь лить воду. P>Зачем? Прямой ответ уже был даден. Раз вы продолжаете вопрошать, значит вам точно надо чтото другое. Играйте в свои игры без меня.
Где?
>>Мой поинт в том, что моки это не про то как пишется код, функциями, классами или чёртом лысым, а про внешние зависимости. И никакой правильный дизайн от них не избавляет, т.к. зависимости диктуются требованиями, а не дизайном. Если у тебя есть субд, будут моки, как ни дизайни. Ну или если у тебя хоумпейдж, а там что угодно делай, не важно. P>Зависимости — требованиями, а способ их протаскивания — дизайном. Соответственно, моки это обрезание тех зависимостей, которые вы же сами затолкали куда поглубже, да еще неглядя.
Пофиг. Зависимости надо мокать. Точка. В этом твоём потоке речи единственный факт: "моки это обрезание зависимостей". А остальное — бессмысленные фантазии.
P>>>Что раз Фаулер так делает, то иначе ну никак нельзя? P>·>Нельзя. И ты ещё не показал, что можно. P>Серьёзная логика. А еще Фаулер показал олдскульный жээс и вдвое большее количество кода, чем нужно, даже с его подходом.
Серьёзная, да. Ни показать своё решение, ни улучшить чужое ты не можешь.
P>>>Моки можно всунуть куда угодно, хоть для теста синусов и косинусов, — это ничего не говорит. P>·>Ты говорил, что моки и это всё — это старьё из 00х. Как оказалось — и тут ты налажал, т.к. статья 2023 года имеет те же самые "устаревшие" моки. P>Статья совсем про другое, о чем сам же Фаулер и пишет — про композицию функций. А вы там только моки видите.
Ну покажи код без моков.
P>>>Именно это вы и говорите. Ну, как вариант, не читаете. P>·>Ты нафантазировал "на реальной бд", а я писал "на бд близкой к боевой (только не по количеству записей, а по качеству)". Разницу не видишь, да? P>Небольшая разница — Data complexity говорит о том, что вам не покрыть и ничтожной части вариантов вашими тестами.
Покажи пример кода.
P>>> Согласованность, транзакционность, задержка — это всё НЕФУНКЦИОНАЛЬНЫЕ. P>·>Как это? Возможность поизменять пользователя после его создания — это функциональное требование. P>А так — в контроллере останется ровно то, что требуется для функциональных требований. А вот всё остальное вам придется распихивать, например, в ту же очередь. И вот такие изменения ломают и ваши моки, и тесты на них.
Изменения ломают моки только если они изменяют функциональность.
P>>>Т.е., условно, вы выяснили, что не успеваете, опаньки! И надо выталкивать процессинг в очередь. Упс — написали тесты, покрыли моками, выбросили моки, переписали тесты, но уже на других моках, ой... P>·>Это требует согласования с бизнесом, а не просто так, чтобы не было тех чудес как у тебя бывает. P>Я так вижу, бизнес вам имена классов и названия методов диктует, да еще 100500 готовых тестов подкидывает.
Раньше после нажатия на кнопочку "создать" появлялась кнопочка "поменять" и она работала, но ты сделал очень такое "нефункциональное" изменение, и теперь эту кнопочку можно нажимать только через пять минут, а до этого какие-то невнятные ошибки. Молодец, чё, а юзерам всегда можно сказать "have you tried to turning it on and off again?". Зато тесты не сломались!
P>>>Интеграция начинается с момента, когда одна ваша функция вызывает другую вашу функцию. Конформационный тест требует запуска приложения или подсистемы, что автоматически означает интеграционный уровень. P>·>Нет, конформационный тест не требует запуска приложения или системы. Читай мою переписку с Sinclair. P>Вы наверное подумали, но забыли написать. Поиск по треду никаких пояснений, как вы используете конформационные тесты, не дал. Тут
.
P>Могу рассказать, как это делается при реализации клиента под протокол — у вас есть 100500 эталонов на все случаи жизни, которые должен проглотить ваш клиент. P>Ровно так же поступают и с компилятором — запускают и прогоняют 100500 примеров кода по спецификации.
Аналогом твоего решения будет тестировать, что функция createUser компилируется в конкретный ассемблерный код.
P>Если вы сами пишете фильтры — а именно такую задачу я вам предложил, то это ваша ответсвенность учесть все возможные кейсы того, как хранятся и кодируются данные в бд — имена колонок, таблиц, строк, подстрок, кусков json, итд итд. P>Фактически, вы пишете ни больше, ни меньше, а небольшой компилятор из json в sql. Только у вас нет этих самых эталонов — под вашу бд и придумки их никто не заготовил.
Вот я и не понимаю каким образом ты собираешься проверять, что этот самый sql выдаёт хоть какие-то правильные данные, а не > кто-то перепутал с < на какой-то комбинации входных данных. И не один раз "проверить" (а на самом деле скопипастить из реализации в тест) в процессе набора кода, но и для регрессии.
P>·>Я не знаю что ты в этом месте понимаешь под "паттерн", но я всегда имел в виду твой конкретный "const pattern =" вот тут
. Такой паттерн вручную прповерять — большая беда, надо тестировать с бд автоматически. P>Похоже, вы что Фаулера, что меня, понимаете както слишком буквально. Я вам показал перевод из рабочего в минимально понятный здесь, вне контекста.
Конечно, я ни телепатией, ни безграничной фантазией не обладаю. Что написано, то и читаю.
P>1. получили рабочий паттерн P>2. строим маппер вокруг этого паттерна
Что за маппер вокруг паттерна? У тебя маппер был частью паттерна как transformations: out:[fn1]
P>п1 — паттерн тестируется на бд, далее — интеграционными тестами
Тут два варианта:
Этих паттернов будут на каждый сценарий/юнит-тест. Т.е. кол-во ручного тестирования и и-тестов получается такое же. Следовательно смысла от таких тестов ноль.
Этих паттерны не будут покрываться интеграцией, а значит опечатки в тексте sql скопипасченные из реализации в тест и регрессии будут обнаруживаться только на проде юзерами.
P>п2 — построение запроса тестируется как все мапперы, без исключения P>Без п2 вы спокойно напоретесь на кейс с уязвимостью, или поломкой на энкодинге данных, или с (не)подтягиванием данных из (не)тех таблиц
У тебя что-то очень не то с дизайном, что у тебя какие-то технические детали с энкодингом данных намешаны с бизнес-логикой реализации сценариев.
P>>>- сервис или бд или сторадж требует эспейпить, энкодить, инлайнить, склеивать, подставлять итд и тд P>·>Так это сервис требует, а не твоя бизнес-логика, это и будет конф-тест тестировать. P>Подробнее — кто и где выдаст вам конф-тест, что запросы смогут внятн что работать с такими вещами — email в таблице users это сам емейл строкой, а email в таблице reply будет mailto:<email>, а в customer он будет в колонке типа json с названием поля 'details' который есть список имя-значение.
Я не понял что ты тут спрашиваешь. Какой ещё емейл?
P>>>Фильтр который вы пишете, это ровно такой же специализированый клиент. И тут, о чудо, можно обходиться без всех таких кейсов P>·>Это будет код и тесты клиента для протокола, а не код бизнес-логики твеого приложения, которое этого клиента использует. P>А разница то какая? Вы одну часть тестов назвали другим именем, от этого сложность поменялась?
Поменялась, т.к. отделили мух от котлет. И вместо умножения комбинаций, мы тестируем их сумму.
Т.е. правила енкодинга определяются для типов данных, например, в строках надо non-ascii енкодить. А бизнес-логика работает со значениниями. И все значения firstname/lastname/&c это строки, енкодинг которых уже покрыт. И не надо отдельно проверять что каждое поле правильно енкодится.
P>>>Где взять боевые данные за февраль 2025го? Вы в курсе, что сейчас 2024й год ? P>·>Не знаю, ты рассказывай, ведь тебе требуется "Рабочий паттерн или нет — это проверяется на бд, в идеале, той, что содержит реальные данные". Рассказывай где-ты берёшь реальные данные за 2025 год для проверки работосбособности твоих паттернов. P>Мне нужно всего лишь паттерн проверить,
А как ты его проверишь-то?
P>а не конечный запрос, как у вас. Потому мне в будущее заглядывать не надо, цитирую себя "тестом бд минимально заполненой под задачу"
Ты уже запамятовал? Ты показывал код, где у тебя в паттерне был конечный запрос.
P>>>Я уже третий месяц рассказываю как именно это нужно тестировать. P>·>Меня ответы "никак", "руками", "используя реальные данные за 2025 год" не устраивают. А с другими ответами ты не соглашаешься.
P>Смотрите внимательно — объяснение ниже я вам приводил уже около десятка раз
Это всё вода. Ты показал конкретный код, я указал в этом конкретном коде конкретную проблему. Ты теперь заявляешь что что-то мне объяснял. Без кода объяснения идут в топку. Я никогда не просил ничего объяснять, я просил показать код.
P>·>Разница значительна: "Работает ли" — важно и нужно тестировать, инвариант диктуемый бизнесом, "строится ли" — это мелкие детали имплементации, которые меняются постоянно. P>Вы что, не помните как в школе на математике или физике подгоняли решение под ответ? Правильный паттерн, некорректно построен, ответ верный — "Молодец, садись, два балла!".
Мы говорим о тестах. В коде теста есть паттерн который туда кто-то как-то напечатал, хз как. Ты так и не рассказал как убедиться что этот самый код корректный. "погонять запрос вручную в sql-консоли" — это был твой лучший ответ. И этот ответ сильно хуже моего ответа "погонять запрос автоматически". Так что ты опять занялся софизмами.
P>Т.е. это те самые ошибки которые вы на тестах бд не увидите. Но они видны при построении запроса.
Как они видны-то? Где что красненьким подчеркнётся?
P>>>А дальше нужно покрыть тестами всю мелочевку — построение запроса таким образом, что бы получался рабочий паттерн P>·>Отстой. P>Ну да, Фаулер пока не написал такую статью. Ждите еще 20 лет
А вы тестируйте в проде.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
>>>Мой поинт в том, что моки это не про то как пишется код, функциями, классами или чёртом лысым, а про внешние зависимости. И никакой правильный дизайн от них не избавляет, т.к. зависимости диктуются требованиями, а не дизайном. Если у тебя есть субд, будут моки, как ни дизайни. Ну или если у тебя хоумпейдж, а там что угодно делай, не важно. P>>Зависимости — требованиями, а способ их протаскивания — дизайном. Соответственно, моки это обрезание тех зависимостей, которые вы же сами затолкали куда поглубже, да еще неглядя. ·>Пофиг. Зависимости надо мокать. Точка. В этом твоём потоке речи единственный факт: "моки это обрезание зависимостей". А остальное — бессмысленные фантазии.
Вы раз за разом повторяете что верите в моки. Зачем? Это ж не аргумент, зато выглядит смешно.
Зависимости нужно учитывать в тестах
1. классический — убираем их целиком, что есть особенность дизайна
2. моки — собственно, пишем моки, код можно писать как попало
В первом случае у нас приложение будет похоже вот на такой слоеный пирог, где 0 это точка отсчета
3 - контроллер - линейный код
2 - use case - именно здесь вызывается DB, этот код делаем максимально линейным
1 - BL - чистая
0 - модель - чистая
Второй вариант, ваш любимый
3 - контроллер
1 - BL грязная, DTO и есть наша модель, вызывает DB или напрямую DAL, или через ваши репозитории, итд, что требует инжекции
0 - DB
P>>Серьёзная логика. А еще Фаулер показал олдскульный жээс и вдвое большее количество кода, чем нужно, даже с его подходом. ·>Серьёзная, да. Ни показать своё решение, ни улучшить чужое ты не можешь.
Я вам уже много раз предлагал посмотреть clean architecture, глянуть, как там работают с бд. Вы хотите что бы я все это пересказал вам здесь?
P>>А так — в контроллере останется ровно то, что требуется для функциональных требований. А вот всё остальное вам придется распихивать, например, в ту же очередь. И вот такие изменения ломают и ваши моки, и тесты на них. ·>Изменения ломают моки только если они изменяют функциональность.
У вас функциональность это весьма расплывчатое понятие. Туда разве что каменты не входят. Или входят?
·>Раньше после нажатия на кнопочку "создать" появлялась кнопочка "поменять" и она работала, но ты сделал очень такое "нефункциональное" изменение, и теперь эту кнопочку можно нажимать только через пять минут, а до этого какие-то невнятные ошибки. Молодец, чё, а юзерам всегда можно сказать "have you tried to turning it on and off again?". Зато тесты не сломались!
Кто вам такое сказал? Вам нужно редактировать не все отношения юзера, а только user-facing. Все остальное вы вас не заботит.
P>>Вы наверное подумали, но забыли написать. Поиск по треду никаких пояснений, как вы используете конформационные тесты, не дал. ·>Тут
нами был напилен набор интеграционных тестов, которые гонялись в каждом acceptance. И мы чаще всего ловили там не глюки нашего софта (которые были отловлены юнит-тестами), а регрессию со стороны Microsoft .
S>Было всего несколько случаев, когда поведение API было не таким, как мы ожидали, и это не было признано багом.
Это называется conformance tests.
То есть, здесь вы назвали интеграционные тесты conformance.
Если вы все еще не согласны — объясните внятно
1 кто пишет эти conformance tests
2 какой код должен выполниться, что бы пройти эти тесты
Ощущение, что вы путаете вид тестов и уровень. Уровень — сколько строк, компонентов, ид задействуется при тесте — юниты, и интеграционные, куда относятся компоненты, функциональные, приложение, система.
Вид — контрактные, конформанс, пенетрейшн, перформанс, e2e, на моках, без моков, приемочные, итд
Конформанс — интеграционные. По определению.
P>>Ровно так же поступают и с компилятором — запускают и прогоняют 100500 примеров кода по спецификации. ·>Аналогом твоего решения будет тестировать, что функция createUser компилируется в конкретный ассемблерный код.
Незачем — у нас трансляция json -> sql.
P>>Фактически, вы пишете ни больше, ни меньше, а небольшой компилятор из json в sql. Только у вас нет этих самых эталонов — под вашу бд и придумки их никто не заготовил. ·>Вот я и не понимаю каким образом ты собираешься проверять, что этот самый sql выдаёт хоть какие-то правильные данные, а не > кто-то перепутал с < на какой-то комбинации входных данных. И не один раз "проверить" (а на самом деле скопипастить из реализации в тест) в процессе набора кода, но и для регрессии.
Я ж вам объяснил раз пять
1. находим паттерн и проверяем его
2. пишем маппер вокруг паттерна и проверяем маппер
Нам нужны и 1 и 2.
Если 1 без 2, то всё в порядке — запрос работает на тестовых данных, но в проде вгружает всю БД в память, потому что подстановки параметров работают только для тестов
Если 2 без 1, то хер его знает, что там делается вообще
А если и 1, и 2, то
1. благодаря правильному паттерну у нас рабочая схема
2. благодаря 2 у нас правильные подстановки в этот паттерн
P>>1. получили рабочий паттерн P>>2. строим маппер вокруг этого паттерна ·>Что за маппер вокруг паттерна? У тебя маппер был частью паттерна как transformations: out:[fn1]
А название таблицы само выросло, да? Подстановка параметров, условий, названий колонок, таблиц, подстановка fn1 и fn2 тоже само? Это именно работа маппера — по json получить рабочий запрос, который будет соответствовать нашим ожиданиям
Это нужно на тот случай, если некто решит сделать "быстрый маленький фикс" после того, как вы уволитесь и контролировать код перестанете
·>Этих паттернов будут на каждый сценарий/юнит-тест. Т.е. кол-во ручного тестирования и и-тестов получается такое же. Следовательно смысла от таких тестов ноль.
В вашей схеме ровно так же. Только вы построение запроса никак не контролируете.
·>Этих паттерны не будут покрываться интеграцией, а значит опечатки в тексте sql скопипасченные из реализации в тест и регрессии будут обнаруживаться только на проде юзерами.
Вы в адеквате? Я ж сказал — интеграционные тесты никуда не деваются. А вы читаете чтото своё.
P>>п2 — построение запроса тестируется как все мапперы, без исключения P>>Без п2 вы спокойно напоретесь на кейс с уязвимостью, или поломкой на энкодинге данных, или с (не)подтягиванием данных из (не)тех таблиц ·>У тебя что-то очень не то с дизайном, что у тебя какие-то технические детали с энкодингом данных намешаны с бизнес-логикой реализации сценариев.
Причин сломать построение запроса при валидном паттерне — огромной количество — например, пупутать названия таблиц, колонок, приоритет операторов итд и тди итд.
P>>Подробнее — кто и где выдаст вам конф-тест, что запросы смогут внятн что работать с такими вещами — email в таблице users это сам емейл строкой, а email в таблице reply будет mailto:<email>, а в customer он будет в колонке типа json с названием поля 'details' который есть список имя-значение. ·>Я не понял что ты тут спрашиваешь. Какой ещё емейл?
Я вам пример привел, что построение запроса по json должно учитывать схему бд. Вот это и проверяем. В каких то случаях невалидный запрос может выдавать данные очень похожие на правильные, и это вполне себе реальная проблема.
·>Т.е. правила енкодинга определяются для типов данных, например, в строках надо non-ascii енкодить. А бизнес-логика работает со значениниями. И все значения firstname/lastname/&c это строки, енкодинг которых уже покрыт. И не надо отдельно проверять что каждое поле правильно енкодится.
Кто будет проверять, что email может энкодиться десятком способов в вашей бд? Подробнее. Ну вот досталось вам от предшественника такое. Ваши действия?
·>А как ты его проверишь-то?
Примерно так же, как и вы. Только проверка паттерна мало что гарантирует. См выше про загрузку всей бд в память. Паттерн корректный, ошибочка при рендеринге некоторых комбинаций фильтров.
P>>а не конечный запрос, как у вас. Потому мне в будущее заглядывать не надо, цитирую себя "тестом бд минимально заполненой под задачу" ·>Ты уже запамятовал? Ты показывал код, где у тебя в паттерне был конечный запрос.
Это выхлоп билдера запросов. не рукописный sql, а результат билдера. Соответсвенно, мы можем проверить работу сложного маппера json -> sql, при чем гораздо плотнее, чем вашими косвенными тестами.
Например, я могу просто заложиться на юнит-тест, и потребовать двойную фильтрацию — первая по периоду, вторая — по параметрам, или вставить limit x, итд итд
И у меня точно не будет кейса "вгружаем всю бд в память".
Даже если в интеграционных тестах у меня не будет 100_000_000_000 записей, ничего страшного — запрос всё равно будет с безопасной структурой.
P>>Смотрите внимательно — объяснение ниже я вам приводил уже около десятка раз ·>Это всё вода. Ты показал конкретный код, я указал в этом конкретном коде конкретную проблему. Ты теперь заявляешь что что-то мне объяснял. Без кода объяснения идут в топку. Я никогда не просил ничего объяснять, я просил показать код.
Правильнее сказать, что вам непонятно, почему ваш подход не будет работать, а мой — будет.
Ваш никак не учитывает data complexity. Мой — именно на этом и строится, см пример выше про 100_000_000_000 записей.
Т.е. мне нужно
1. быть в курсе про возможную проблему с загрузкой конской таблицы из за ошибок в построении фильтров
2. найти решение
3. зафиксировать теми тестами, которые вам кажутся лишними
А вот вы так и не показали тест "никогда не будем загружать всю бд в память". Вы показали другой совсем другой тест — загрузим 1, если только что записали 1.
·>Мы говорим о тестах. В коде теста есть паттерн который туда кто-то как-то напечатал, хз как. Ты так и не рассказал как убедиться что этот самый код корректный. "погонять запрос вручную в sql-консоли" — это был твой лучший ответ.
Читаем вместе:
п1 — паттерн тестируется на бд, далее — интеграционными тестами
Сколько бы я ни писал про интеграционные тесты, вам мерещится "погонять вручную"
Это какая то особенность вашего восприятия
·>Как они видны-то? Где что красненьким подчеркнётся?
См выше, "никогда не будем загружать всю бд в память" — для этого кейса у вас ни одного теста, а у меня хоть какие то.
Здравствуйте, Pauel, Вы писали:
>>>>Мой поинт в том, что моки это не про то как пишется код, функциями, классами или чёртом лысым, а про внешние зависимости. И никакой правильный дизайн от них не избавляет, т.к. зависимости диктуются требованиями, а не дизайном. Если у тебя есть субд, будут моки, как ни дизайни. Ну или если у тебя хоумпейдж, а там что угодно делай, не важно. P>>>Зависимости — требованиями, а способ их протаскивания — дизайном. Соответственно, моки это обрезание тех зависимостей, которые вы же сами затолкали куда поглубже, да еще неглядя. P>·>Пофиг. Зависимости надо мокать. Точка. В этом твоём потоке речи единственный факт: "моки это обрезание зависимостей". А остальное — бессмысленные фантазии. P>Вы раз за разом повторяете что верите в моки. Зачем? Это ж не аргумент, зато выглядит смешно.
Без моков внешних зависимостей ты не можешь тестировать свой код если эта самая зависимость по разным причинам недоступна.
P>>>Серьёзная логика. А еще Фаулер показал олдскульный жээс и вдвое большее количество кода, чем нужно, даже с его подходом. P>·>Серьёзная, да. Ни показать своё решение, ни улучшить чужое ты не можешь. P>Я вам уже много раз предлагал посмотреть clean architecture, глянуть, как там работают с бд. Вы хотите что бы я все это пересказал вам здесь?
Нет, я хочу чтобы ты код показал.
P>·>Раньше после нажатия на кнопочку "создать" появлялась кнопочка "поменять" и она работала, но ты сделал очень такое "нефункциональное" изменение, и теперь эту кнопочку можно нажимать только через пять минут, а до этого какие-то невнятные ошибки. Молодец, чё, а юзерам всегда можно сказать "have you tried to turning it on and off again?". Зато тесты не сломались! P>Кто вам такое сказал? Вам нужно редактировать не все отношения юзера, а только user-facing. Все остальное вы вас не заботит.
Не распарсил.
P>То есть, здесь вы назвали интеграционные тесты conformance.
Наверное я плохо выразился, я не назвал, я возразил, что такие вещи надо не интеграционными тестами тестировать а конформационными, иначе будет беда с процессом релиза когда внешние система(ы) недоступны. Цитирую: "мы можем пройти acceptance для нашего проекта только в момент когда _все_ внешние тестовые системы работают".
У Sinclair был тривиальнейший случай "когда мы работали с CREST API от Microsoft". Т.е. внешняя зависимость одна и от более-менее надёжного вендора, у которого обычно всё работает. В более-менее больших сложных проектах такой халявы не бывает.
P>Если вы все еще не согласны — объясните внятно P>1 кто пишет эти conformance tests
Мы.
P>2 какой код должен выполниться, что бы пройти эти тесты
Код этих тестов. Поднимать само приложение для этого не нужно. Никакой интеграции. Цитирую: "Conformance tests можно гонять независимо от наших релизов".
P>>>Ровно так же поступают и с компилятором — запускают и прогоняют 100500 примеров кода по спецификации. P>·>Аналогом твоего решения будет тестировать, что функция createUser компилируется в конкретный ассемблерный код. P>Незачем — у нас трансляция json -> sql.
Опять у тебя мешанина. Тогда это будет метод translateJsonToSql , а не бизнес-специфичный createUser. Тесты createUser должны тестировать создание юзера, а не трансляцию json.
P>>>Фактически, вы пишете ни больше, ни меньше, а небольшой компилятор из json в sql. Только у вас нет этих самых эталонов — под вашу бд и придумки их никто не заготовил. P>·>Вот я и не понимаю каким образом ты собираешься проверять, что этот самый sql выдаёт хоть какие-то правильные данные, а не > кто-то перепутал с < на какой-то комбинации входных данных. И не один раз "проверить" (а на самом деле скопипастить из реализации в тест) в процессе набора кода, но и для регрессии. P>Я ж вам объяснил раз пять P>1. находим паттерн и проверяем его
Где находим? Как проверяем? Когда проверяем?
P>1. благодаря правильному паттерну у нас рабочая схема P>2. благодаря 2 у нас правильные подстановки в этот паттерн
Я не понял детали. Код покажи.
P>·>Что за маппер вокруг паттерна? У тебя маппер был частью паттерна как transformations: out:[fn1] P>А название таблицы само выросло, да? Подстановка параметров, условий, названий колонок, таблиц, подстановка fn1 и fn2 тоже само? Это именно работа маппера — по json получить рабочий запрос, который будет соответствовать нашим ожиданиям P>Это нужно на тот случай, если некто решит сделать "быстрый маленький фикс" после того, как вы уволитесь и контролировать код перестанете
Да ты меня запутал. Была и трансляция, и трансформация, и маппер, и паттерн, и ещё чего. Я уже перестал понимать кто на ком стоял.
P>·>Этих паттернов будут на каждый сценарий/юнит-тест. Т.е. кол-во ручного тестирования и и-тестов получается такое же. Следовательно смысла от таких тестов ноль. P>В вашей схеме ровно так же. Только вы построение запроса никак не контролируете.
Не правда, что ровно так же. Ручное тестирование исключается, т.к. есть тесты репо+бд. А построение не контролирую, потому что считаю что запрос не важно как строится, т.к. это детали реализации, важно что запрос работает в соответствии с бизнес-ожиданиями. Конкретный пример когда это не сработает я так и не увидел.
P>·>Этих паттерны не будут покрываться интеграцией, а значит опечатки в тексте sql скопипасченные из реализации в тест и регрессии будут обнаруживаться только на проде юзерами. P>Вы в адеквате? Я ж сказал — интеграционные тесты никуда не деваются. А вы читаете чтото своё.
Не деваются, но такие тесты которые ты имеешь в виду (проверяющие интеграцию в контроллере всего со всем) не могут покрыть все возможные комбинации.
В моей схеме будут тесты репо+бд, которые тестируют только часть системы, относящуюся к персистенсу.
P>>>п2 — построение запроса тестируется как все мапперы, без исключения P>>>Без п2 вы спокойно напоретесь на кейс с уязвимостью, или поломкой на энкодинге данных, или с (не)подтягиванием данных из (не)тех таблиц P>·>У тебя что-то очень не то с дизайном, что у тебя какие-то технические детали с энкодингом данных намешаны с бизнес-логикой реализации сценариев. P>Причин сломать построение запроса при валидном паттерне — огромной количество — например, пупутать названия таблиц, колонок, приоритет операторов итд и тди итд.
Именно, для этого и нужны тесты репо+бд. А при наличии таких тестов писать тесты ещё и на построение запросов — неясно зачем.
P>·>Я не понял что ты тут спрашиваешь. Какой ещё емейл? P>Я вам пример привел, что построение запроса по json должно учитывать схему бд. Вот это и проверяем. В каких то случаях невалидный запрос может выдавать данные очень похожие на правильные, и это вполне себе реальная проблема.
Ты так и не рассказал как _тестировать_ валидность запроса. Сравнение с твоим pattern ничего о валидности не говорит.
P>·>Т.е. правила енкодинга определяются для типов данных, например, в строках надо non-ascii енкодить. А бизнес-логика работает со значениниями. И все значения firstname/lastname/&c это строки, енкодинг которых уже покрыт. И не надо отдельно проверять что каждое поле правильно енкодится. P>Кто будет проверять, что email может энкодиться десятком способов в вашей бд? Подробнее. Ну вот досталось вам от предшественника такое. Ваши действия?
В смысле "действия"? Тестами покрывать что есть — разбираться какие способы существуют в легаси и воспроизводить в тестах. И потом потихоньку мигрировать легаси, например.
P>·>А как ты его проверишь-то? P>Примерно так же, как и вы. Только проверка паттерна мало что гарантирует. См выше про загрузку всей бд в память. Паттерн корректный, ошибочка при рендеринге некоторых комбинаций фильтров.
Я до сих пор не понимаю почему у тебя есть проблема с загрузкой всей бд в память, решается же элементарно.
P>>>а не конечный запрос, как у вас. Потому мне в будущее заглядывать не надо, цитирую себя "тестом бд минимально заполненой под задачу" P>·>Ты уже запамятовал? Ты показывал код, где у тебя в паттерне был конечный запрос. P>Это выхлоп билдера запросов. не рукописный sql, а результат билдера. Соответсвенно, мы можем проверить работу сложного маппера json -> sql, при чем гораздо плотнее, чем вашими косвенными тестами. P>Например, я могу просто заложиться на юнит-тест, и потребовать двойную фильтрацию — первая по периоду, вторая — по параметрам, или вставить limit x, итд итд P>И у меня точно не будет кейса "вгружаем всю бд в память". P>Даже если в интеграционных тестах у меня не будет 100_000_000_000 записей, ничего страшного — запрос всё равно будет с безопасной структурой.
Как ты отличишь в тесте запрос с безопасной структурой от запроса с небезопасной?
P>>>Смотрите внимательно — объяснение ниже я вам приводил уже около десятка раз P>·>Это всё вода. Ты показал конкретный код, я указал в этом конкретном коде конкретную проблему. Ты теперь заявляешь что что-то мне объяснял. Без кода объяснения идут в топку. Я никогда не просил ничего объяснять, я просил показать код. P>Правильнее сказать, что вам непонятно, почему ваш подход не будет работать, а мой — будет.
Ага, это я давно пытаюсь из тебя выудить. И в виде кода, а не вилами по воде.
P>Ваш никак не учитывает data complexity. Мой — именно на этом и строится, см пример выше про 100_000_000_000 записей.
Бла-бла-бла.
P>Т.е. мне нужно P>1. быть в курсе про возможную проблему с загрузкой конской таблицы из за ошибок в построении фильтров P>2. найти решение P>3. зафиксировать теми тестами, которые вам кажутся лишними
Если у тебя не получается это зафиксировать это нормальными тестами, то создай новый топик, поможем, не бином ньютона.
P>А вот вы так и не показали тест "никогда не будем загружать всю бд в память".
Ты тоже такой тест не показал.
P> Вы показали другой совсем другой тест — загрузим 1, если только что записали 1.
Я такой тест не показывал.
P>·>Мы говорим о тестах. В коде теста есть паттерн который туда кто-то как-то напечатал, хз как. Ты так и не рассказал как убедиться что этот самый код корректный. "погонять запрос вручную в sql-консоли" — это был твой лучший ответ. P>Читаем вместе: P>
P>п1 — паттерн тестируется на бд, далее — интеграционными тестами
Где? Как? Напомню, у тебя было: deep.eq(pattern). В каком тут месте "тестируется на бд"?
P>Сколько бы я ни писал про интеграционные тесты, вам мерещится "погонять вручную"
У тебя интеграционные тесты тестируют каждый паттерн?
P>Это какая то особенность вашего восприятия
Я воспринимаю то что написано, а не фантазирую.
P>·>Как они видны-то? Где что красненьким подчеркнётся? P>См выше, "никогда не будем загружать всю бд в память" — для этого кейса у вас ни одного теста, а у меня хоть какие то.
Ну потому что ты "1. был в курсе" и написал хоть какой-то тест. Т.е. они были не видны, как ты обещал, а у вас видимо на проде у вас что-то навернулось и ты это "увидел".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Sinclair, Вы писали:
S>Теперь остаётся всё это склеить. Риск при склейке минимален — просто потому, что в ней очень мало кода:
S>DateTime.now()
S> .GetReportDateRange()
...
S>Я не отказываю этому коду в шансе содержать ошибку — действительно, мы могли напороть примерно везде.
По-моему я не донёс эту мысль. Да, совершенно верно: "Риск при склейке минимален — просто потому, что в ней очень мало кода". Настоящая проблема в том, что тут у нас как правило не одна "плохая зависимость" как DateTime.now(); и этот код склейки будет в каждой мелкой бизнес-операции приложения. Т.е. в каждом контроллере мало кода, да, но в реальной большой системе зависимостей будет больше, контроллеров сотни-тысячи, этот "минимальный риск" надо возводить в тысячную степень и ВНЕЗАПНО риск получается серьёзным, и тестами прикрыть себе пятую точку не выйдет, т.к. "DateTime.now()" не тестируемо.
Суть всех этих модулей, слоёв, composition root, &c — минимизировать общее количество такого кода склейки. И максимизировать покрытие тестами в том числе и кода склейки.
S>Такие вещи ловятся интеграционным тестированием, которое один хрен нужно проводить.
А что ты в таком тесте, зависящем от DateTime.now() (и ещё пачки внешних зависимостей в неизвестном тесту состоянии) будешь ассертить? Ведь каждый раз у тебя будут выдаваться потенциально совершенно разные результаты. Ну выдался отчёт с 0 строк — тест пройден или как?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
P>>Вы раз за разом повторяете что верите в моки. Зачем? Это ж не аргумент, зато выглядит смешно. ·>Без моков внешних зависимостей ты не можешь тестировать свой код если эта самая зависимость по разным причинам недоступна.
Слишком категорично. Правильно так — часть тестов прогнать не получится. Соответсвенно в моки можно выносить не вообще всё, а только такие кейсы, без которых ну никак нельзя.
P>>Я вам уже много раз предлагал посмотреть clean architecture, глянуть, как там работают с бд. Вы хотите что бы я все это пересказал вам здесь? ·>Нет, я хочу чтобы ты код показал.
Это и есть пересказ всего, что изложено в clean architecture. Я уже приводил пример, вы прицепились к проверке sql и до сих пор успокоиться не можете.
Какой смысл приводить еще один пример, если вы еще на предыдущий продолжаете наскакивать?
P>>Кто вам такое сказал? Вам нужно редактировать не все отношения юзера, а только user-facing. Все остальное вы вас не заботит. ·>Не распарсил.
Очень просто — редактироавние после записи нужно для конкретных целей, например — что бы администратор мог подправить свойства только что созданного юзера, а не ждать пять минут.
Соответсвенно, в самом запросе мы обеспечиваем ровно этот минимум, а вообще всё, включая паблик кей спейса юзера
Если ваш бизнес аналиитк затребовал вообще всё такое — то вы приплыли.
P>>То есть,в т здесь вы назвали интеграционные тесты conformance. ·>Наверное я плохо выразился, я не назвал, я возразил, что такие вещи надо не интеграционными тестами тестировать а конформационными, иначе будет беда с процессом релиза когда внешние система(ы) недоступны. Цитирую: "мы можем пройти acceptance для нашего проекта только в момент когда _все_ внешние тестовые системы работают".
А как понять из ваших конформационных тестов, что ваши фильтры не будут вгружать вообще всё из вашей же местной бд?
P>>Если вы все еще не согласны — объясните внятно P>>1 кто пишет эти conformance tests ·>Мы.
P>>2 какой код должен выполниться, что бы пройти эти тесты ·>Код этих тестов. Поднимать само приложение для этого не нужно. Никакой интеграции. Цитирую: "Conformance tests можно гонять независимо от наших релизов".
Непонятно. Это вы тестируете внешние зависимости что ли? Непонятно. Как это к задаче с фильтрами относится?
P>>Незачем — у нас трансляция json -> sql. ·>Опять у тебя мешанина. Тогда это будет метод translateJsonToSql , а не бизнес-специфичный createUser. Тесты createUser должны тестировать создание юзера, а не трансляцию json.
Совсем необязательно. Частный случай маппера проще написать, проще протестировать. обобщенный translateJsonToSql это забег на месяцы или даже годы. Соответсвенно, наш маппер будет просто выдавать запрос createUser, в том виде, как требуется под именно эту задачу
1. все маппинги, с учетом всех дикостей схемы и бд
2. параметры
3. выражение, приоритеты
4. и энкодинг, без этого никуда
В вашем случае вы 1, 2, 3 и 4 будете проверять косвенными тестами, которые заведомо дырявые.
P>>Я ж вам объяснил раз пять P>>1. находим паттерн и проверяем его ·>Где находим? Как проверяем? Когда проверяем?
Извините, но вам стоит читать внимательнее. Я последее время слишком часто цитирую самого себя. Не можете удерживать контекст — чего вам неймется, "в интернете ктото неправ"?
P>>1. благодаря правильному паттерну у нас рабочая схема P>>2. благодаря 2 у нас правильные подстановки в этот паттерн ·>Я не понял детали. Код покажи.
Все код был даден, отмотайте и посмотрите, это всё та же структурная эквивалентность запроса к бд.
P>>Это нужно на тот случай, если некто решит сделать "быстрый маленький фикс" после того, как вы уволитесь и контролировать код перестанете ·>Да ты меня запутал. Была и трансляция, и трансформация, и маппер, и паттерн, и ещё чего. Я уже перестал понимать кто на ком стоял.
маппер — по json строит конкретный запрос, createUser
паттерн — основа этого запроса
трансформация — часть маппера, трансформируем json в нужный нам вид, на выходе — делаем обратное преобразование.
P>>В вашей схеме ровно так же. Только вы построение запроса никак не контролируете. ·>Не правда, что ровно так же. Ручное тестирование исключается, т.к. есть тесты репо+бд. А построение не контролирую, потому что считаю что запрос не важно как строится, т.к. это детали реализации, важно что запрос работает в соответствии с бизнес-ожиданиями. Конкретный пример когда это не сработает я так и не увидел.
Я вам продолжаю приводить тот же самый пример — фильтры, когда из за ошибки в построении запроса вгружается вся бд. Вы его усиленно игнорируете.
P>>Вы в адеквате? Я ж сказал — интеграционные тесты никуда не деваются. А вы читаете чтото своё. ·>Не деваются, но такие тесты которые ты имеешь в виду (проверяющие интеграцию в контроллере всего со всем) не могут покрыть все возможные комбинации.
Зато sql в этих тестах как раз так выполняется, и проходит тот самый чек, что и у вас.
А раз покрыть все комбинации не получится, то незачем и пытаться — нужно переложить критические кейсы на другие методы.
·>В моей схеме будут тесты репо+бд, которые тестируют только часть системы, относящуюся к персистенсу.
И как вы протестируете, что у вас невозможна ситуация, что прод вгружает вообще всё?
P>>Причин сломать построение запроса при валидном паттерне — огромной количество — например, пупутать названия таблиц, колонок, приоритет операторов итд и тди итд. ·>Именно, для этого и нужны тесты репо+бд. А при наличии таких тестов писать тесты ещё и на построение запросов — неясно зачем.
Я ж вам говорил — некорректный запрос в тестах может выдавать корректный результат. И примеры привел.
·>Ты так и не рассказал как _тестировать_ валидность запроса. Сравнение с твоим pattern ничего о валидности не говорит.
Валидность вообще всех запросов проверить не выйдет — та самая data complexity. Зато можно проверить известные проблемы для тех случаев, когда точная комбинация входа неизвестна.
P>>Кто будет проверять, что email может энкодиться десятком способов в вашей бд? Подробнее. Ну вот досталось вам от предшественника такое. Ваши действия? ·>В смысле "действия"? Тестами покрывать что есть — разбираться какие способы существуют в легаси и воспроизводить в тестах. И потом потихоньку мигрировать легаси, например.
Это значит, что вам нужно каждый такой кейс или через базу гонять, или же написать маппер, который можно дополнительно покрыть тестами, где учтем все возможные кейсы что есть в бд прода, или нам известно, что такие будут.
P>>Примерно так же, как и вы. Только проверка паттерна мало что гарантирует. См выше про загрузку всей бд в память. Паттерн корректный, ошибочка при рендеринге некоторых комбинаций фильтров. ·>Я до сих пор не понимаю почему у тебя есть проблема с загрузкой всей бд в память, решается же элементарно.
Вы до сих пор не показали решения. Комбинация параметров вам неизвестна. Действуйте.
P>>Даже если в интеграционных тестах у меня не будет 100_000_000_000 записей, ничего страшного — запрос всё равно будет с безопасной структурой. ·>Как ты отличишь в тесте запрос с безопасной структурой от запроса с небезопасной?
В зависимости от задачи. Например — двойная фильтрация. Часть фильтров в самом запросе, ограничивают выборку, не параметризуются, часть — параметры для фильтрации оставшегося.
Теперь что бы вы не подкидывали в фильтр, у вас никогда не будет кейса "вгрузить всё"
P>>А вот вы так и не показали тест "никогда не будем загружать всю бд в память". ·>Ты тоже такой тест не показал.
Тест — показал, только вы его понять не можете.
P>> Вы показали другой совсем другой тест — загрузим 1, если только что записали 1. ·>Я такой тест не показывал.
Это именно ваш подход — записать три значения в бд и надеяться что этого хватит. А как протестировать "запрос не тащит откуда не надо" вы не показали.
P>>Читаем вместе: P>>
P>>п1 — паттерн тестируется на бд, далее — интеграционными тестами
·>Где? Как? Напомню, у тебя было: deep.eq(pattern). В каком тут месте "тестируется на бд"?
Вы дурака валяете? deep.eq.pattern это тест для п2. Тесты для п1 — обычные интеграционные.
P>>Сколько бы я ни писал про интеграционные тесты, вам мерещится "погонять вручную" ·>У тебя интеграционные тесты тестируют каждый паттерн?
По числу юз кейсов. Все юз кейсы должны быть покрыты интеграционными тестами.
P>>См выше, "никогда не будем загружать всю бд в память" — для этого кейса у вас ни одного теста, а у меня хоть какие то. ·>Ну потому что ты "1. был в курсе" и написал хоть какой-то тест. Т.е. они были не видны, как ты обещал, а у вас видимо на проде у вас что-то навернулось и ты это "увидел".
Покрыть все возможные комбинации фильтров тестом с бд — нереально. Вы можете покрыть ну 5, ну 10, ну 50, но если у вас фильтров на страницу — вы ошалеете. Здесь забег на тысячи комбинаций.
На каждую комбинацию накидать минимальную бд — уже мало реально.
Особенно что нужно проверять и кейсы "не тащим откуда не надо"
Т.е. каждая комбинация это тесты вида "тащим откуда надо" + тесты вида "не тащим откуда не надо" коих много больше.
Здравствуйте, Pauel, Вы писали:
P>>>Вы раз за разом повторяете что верите в моки. Зачем? Это ж не аргумент, зато выглядит смешно. P>·>Без моков внешних зависимостей ты не можешь тестировать свой код если эта самая зависимость по разным причинам недоступна. P>Слишком категорично. Правильно так — часть тестов прогнать не получится. Соответсвенно в моки можно выносить не вообще всё, а только такие кейсы, без которых ну никак нельзя.
Всё верно, в этом и мой поинт. Про то, что в моки нужно выносить всё — это ты сам придумал.
P>>>Я вам уже много раз предлагал посмотреть clean architecture, глянуть, как там работают с бд. Вы хотите что бы я все это пересказал вам здесь? P>·>Нет, я хочу чтобы ты код показал. P>Это и есть пересказ всего, что изложено в clean architecture. Я уже приводил пример, вы прицепились к проверке sql и до сих пор успокоиться не можете. P>Какой смысл приводить еще один пример, если вы еще на предыдущий продолжаете наскакивать?
Действительно. Какой смысл искать верное решение задачи, если в предыдущем были ошибки. Отличная логика!
P>>>Кто вам такое сказал? Вам нужно редактировать не все отношения юзера, а только user-facing. Все остальное вы вас не заботит. P>·>Не распарсил. P>Очень просто — редактироавние после записи нужно для конкретных целей, например — что бы администратор мог подправить свойства только что созданного юзера, а не ждать пять минут.
Это вроде очевидное требование. Необходимость пользователям ждать по пять минут перед тем как нажать кнопочку — должно быть серьёзно обоснованно и обговорено с заказчиком. Как ты это вообще представляешь? Кнопочка как обычно рисуется на экране, но пользователям надо в инструкции написать, что "не нажимайте кнопочку быстрее чем через 5 минут". Бред же. Если такое "нефункциональное" изменение вдруг понадобится, то оно потребует заметную переработку UI и т.п. Тесты просто обязаны грохнуться!
P>Соответсвенно, в самом запросе мы обеспечиваем ровно этот минимум, а вообще всё, включая паблик кей спейса юзера P>Если ваш бизнес аналиитк затребовал вообще всё такое — то вы приплыли.
Я не в курсе что такое "паблик кей спейса юзера".
P>>>2 какой код должен выполниться, что бы пройти эти тесты P>·>Код этих тестов. Поднимать само приложение для этого не нужно. Никакой интеграции. Цитирую: "Conformance tests можно гонять независимо от наших релизов". P>Непонятно. Это вы тестируете внешние зависимости что ли? Непонятно. Как это к задаче с фильтрами относится?
Про конформанс я говорил в контексте "CREST API". Фильтры это репо+бд тесты.
P>В вашем случае вы 1, 2, 3 и 4 будете проверять косвенными тестами, которые заведомо дырявые.
Не перекладывай с больной головы. Косвенные тесты как раз у вас, т.к. тестируют не поведение системы, а внутреннюю имплементацию; и с дырами в которые я тебе пальчиком тыкал несколько раз; да ещё и хрупкие.
P>>>Я ж вам объяснил раз пять P>>>1. находим паттерн и проверяем его P>·>Где находим? Как проверяем? Когда проверяем? P>Извините, но вам стоит читать внимательнее. Я последее время слишком часто цитирую самого себя. Не можете удерживать контекст — чего вам неймется, "в интернете ктото неправ"?
Ты ни разу не ответил прямо на этот вопрос.
P>·>Я не понял детали. Код покажи. P>Все код был даден, отмотайте и посмотрите, это всё та же структурная эквивалентность запроса к бд.
Мы рассмотрели этот пример, ты вроде даже признал, что там лажа.
P>>>Это нужно на тот случай, если некто решит сделать "быстрый маленький фикс" после того, как вы уволитесь и контролировать код перестанете P>·>Да ты меня запутал. Была и трансляция, и трансформация, и маппер, и паттерн, и ещё чего. Я уже перестал понимать кто на ком стоял. P>маппер — по json строит конкретный запрос, createUser P>паттерн — основа этого запроса
что за основа? Запроса какого? sql?
P>трансформация — часть маппера, трансформируем json в нужный нам вид, на выходе — делаем обратное преобразование.
Трансформация? Обратная? А что такое transformations? out:...? Это было частью pattern в твоём сниппете. Тут ты говоришь, что это часть маппера.
Ты можешь внятный код написать? Ты уже в своей терминологии сам запутался.
P>·>Не правда, что ровно так же. Ручное тестирование исключается, т.к. есть тесты репо+бд. А построение не контролирую, потому что считаю что запрос не важно как строится, т.к. это детали реализации, важно что запрос работает в соответствии с бизнес-ожиданиями. Конкретный пример когда это не сработает я так и не увидел. P>Я вам продолжаю приводить тот же самый пример — фильтры, когда из за ошибки в построении запроса вгружается вся бд. Вы его усиленно игнорируете.
Я не игнорирую, я уже где-то месяц назад написал как его покрыть нормальным тестом. Это ты игнорируешь мои ответы.
P>>>Вы в адеквате? Я ж сказал — интеграционные тесты никуда не деваются. А вы читаете чтото своё. P>·>Не деваются, но такие тесты которые ты имеешь в виду (проверяющие интеграцию в контроллере всего со всем) не могут покрыть все возможные комбинации. P>Зато sql в этих тестах как раз так выполняется, и проходит тот самый чек, что и у вас.
Он выполняется косвенно, через кучу слоёв: "когда у нас дошла очередь интеграционного тестирования, где (медленно!) тащатся реальные данные из реальной базы, выполняется (медленный!) UI workflow с навигацией от логина до этого отчёта, и т.п.".
Т.е. либо у тебя такие тесты будут гонятся неделями, либо ты сможешь покрыть только ничтожную долю комбинаций этих конкретных запросов.
В моём случае тесты выполняют только связку репо+бд и там можно гонять на порядки больше комбинаций.
P>А раз покрыть все комбинации не получится, то незачем и пытаться — нужно переложить критические кейсы на другие методы.
Вот и неясно зачем вы пытаетесь это перекладывать на эти ваши странные бесполезные тесты, т.к. нужно другие методы использовать.
P>·>В моей схеме будут тесты репо+бд, которые тестируют только часть системы, относящуюся к персистенсу. P>И как вы протестируете, что у вас невозможна ситуация, что прод вгружает вообще всё?
Вы тоже не можете это _протестировать_. Просто ещё этого не поняли.
P>>>Причин сломать построение запроса при валидном паттерне — огромной количество — например, пупутать названия таблиц, колонок, приоритет операторов итд и тди итд. P>·>Именно, для этого и нужны тесты репо+бд. А при наличии таких тестов писать тесты ещё и на построение запросов — неясно зачем. P>Я ж вам говорил — некорректный запрос в тестах может выдавать корректный результат. И примеры привел.
Я примеров не видел. Я видел "объяснения".
P>·>Ты так и не рассказал как _тестировать_ валидность запроса. Сравнение с твоим pattern ничего о валидности не говорит. P>Валидность вообще всех запросов проверить не выйдет — та самая data complexity. Зато можно проверить известные проблемы для тех случаев, когда точная комбинация входа неизвестна.
Как? Ты это Проблему Останова решил тестами?
P>·>В смысле "действия"? Тестами покрывать что есть — разбираться какие способы существуют в легаси и воспроизводить в тестах. И потом потихоньку мигрировать легаси, например. P>Это значит, что вам нужно каждый такой кейс или через базу гонять, или же написать маппер, который можно дополнительно покрыть тестами, где учтем все возможные кейсы что есть в бд прода, или нам известно, что такие будут.
Ложная альтернатива. Ты "забыл" вариант: гонять через базу все возможные кейсы что есть в бд прода, или нам известно, что такие будут.
P>>>Примерно так же, как и вы. Только проверка паттерна мало что гарантирует. См выше про загрузку всей бд в память. Паттерн корректный, ошибочка при рендеринге некоторых комбинаций фильтров. P>·>Я до сих пор не понимаю почему у тебя есть проблема с загрузкой всей бд в память, решается же элементарно. P>Вы до сих пор не показали решения. Комбинация параметров вам неизвестна. Действуйте.
Только после вас.
P>>>Даже если в интеграционных тестах у меня не будет 100_000_000_000 записей, ничего страшного — запрос всё равно будет с безопасной структурой. P>·>Как ты отличишь в тесте запрос с безопасной структурой от запроса с небезопасной? P>В зависимости от задачи. Например — двойная фильтрация. Часть фильтров в самом запросе, ограничивают выборку, не параметризуются, часть — параметры для фильтрации оставшегося. P>Теперь что бы вы не подкидывали в фильтр, у вас никогда не будет кейса "вгрузить всё"
И что ты будешь ассертить в твоём тесте? sql.contains("LIMIT 1000")?
P>>>А вот вы так и не показали тест "никогда не будем загружать всю бд в память". P>·>Ты тоже такой тест не показал. P>Тест — показал, только вы его понять не можете.
Это который? "select * from users"?
P>>> Вы показали другой совсем другой тест — загрузим 1, если только что записали 1. P>·>Я такой тест не показывал. P>Это именно ваш подход — записать три значения в бд и надеяться что этого хватит. А как протестировать "запрос не тащит откуда не надо" вы не показали.
Показал. Запрос должен из условных трёх записей выбирать только условно две.
P>>>
P>>>п1 — паттерн тестируется на бд, далее — интеграционными тестами
P>·>Где? Как? Напомню, у тебя было: deep.eq(pattern). В каком тут месте "тестируется на бд"? P>Вы дурака валяете? deep.eq.pattern это тест для п2. Тесты для п1 — обычные интеграционные.
Я читаю что написано. В цитате выше написано "тестируется" (само как-то?), потом стоит запятая и слово "далее" и про интеграционные тесты. Если эта твоя цитата не говорит что ты хочешь сказать, переформулируй, у меня очень плохо с телепатией.
P>>>Сколько бы я ни писал про интеграционные тесты, вам мерещится "погонять вручную" P>·>У тебя интеграционные тесты тестируют каждый паттерн? P>По числу юз кейсов. Все юз кейсы должны быть покрыты интеграционными тестами.
Давай цифири приведу. В типичном проекте какие мне доводилось наблюдать таких юзкекйсов порядка 100k при более-менее хорошо организованном тестировании. Каждый интеграционный тест вида "...UI workflow с навигацией от логина..." это порядка нескольких секунд, даже без учёта разворачивания и подготовки инфры. Прикинь сколько будет занимать прогон всех таких тестов. В реальности интеграцией можно покрыть от силы 1% кейсов. Если это, конечно, не хоумпейдж.
P>>>См выше, "никогда не будем загружать всю бд в память" — для этого кейса у вас ни одного теста, а у меня хоть какие то. P>·>Ну потому что ты "1. был в курсе" и написал хоть какой-то тест. Т.е. они были не видны, как ты обещал, а у вас видимо на проде у вас что-то навернулось и ты это "увидел". P>Покрыть все возможные комбинации фильтров тестом с бд — нереально. Вы можете покрыть ну 5, ну 10, ну 50, но если у вас фильтров на страницу — вы ошалеете. Здесь забег на тысячи комбинаций. P>На каждую комбинацию накидать минимальную бд — уже мало реально.
Я тебе уже объяснял. Не надо накидывать бд на каждую комбинацию. Какие-то жалкие 30 (тридцать!) записей можно фильтровать миллиардом (230) уникальных способов, без учёта сортироваки.
P>Т.е. каждая комбинация это тесты вида "тащим откуда надо" + тесты вида "не тащим откуда не надо" коих много больше.
Не так, а так: для комбинации X выбираем эти 7 записей из 30.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали: S>>Такие вещи ловятся интеграционным тестированием, которое один хрен нужно проводить. ·>А что ты в таком тесте, зависящем от DateTime.now() (и ещё пачки внешних зависимостей в неизвестном тесту состоянии) будешь ассертить? Ведь каждый раз у тебя будут выдаваться потенциально совершенно разные результаты. Ну выдался отчёт с 0 строк — тест пройден или как?
Смотря чего мы ожидали.
Например, мы точно знаем, как должен выглядеть отчёт за 2023 год — ведь прошлое не меняется. Запускаем, сверяем.
Ничего "потенциально разного" тут не будет, т.к. речь идёт об интеграции с боевой системой, и там мусора не бывает.
Либо мы сверяем интеграцию с Test-In-Production — боевой системой, на которой можно экспериментировать бесплатно.
Тогда интеграционный тест — это прогонка полного цикла типа "создать клиента — зарегистрировать пользователей — выполнить ряд заказов — проверить результаты"
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, ·, Вы писали:
P>>Это и есть пересказ всего, что изложено в clean architecture. Я уже приводил пример, вы прицепились к проверке sql и до сих пор успокоиться не можете. P>>Какой смысл приводить еще один пример, если вы еще на предыдущий продолжаете наскакивать? ·>Действительно. Какой смысл искать верное решение задачи, если в предыдущем были ошибки. Отличная логика!
Вы пока ошибок не показали. Основная ваша придирка в том, что структурная эквивалентность не нужна, хрупкая, итд — при этом альтернативы такому решению у вас нет.
P>>Очень просто — редактироавние после записи нужно для конкретных целей, например — что бы администратор мог подправить свойства только что созданного юзера, а не ждать пять минут. ·>Это вроде очевидное требование. Необходимость пользователям ждать по пять минут перед тем как нажать кнопочку — должно быть серьёзно обоснованно и обговорено с заказчиком. Как ты это вообще представляешь?
Вы снова с колокольни? Ничего ждать не надо — в том то и особенность. И всё работает. Потому как данные по пользователю делятся на две большие части — те, что нужны сейчас, и те, что просто нужны.
Вот например — под нового сотрудника аккаунт создаётся заранее. Здесь заботиться о том, что бы всё-всё-всё(и все гуиды редактировали руками, ага) было доступно к редактированию через 50мс — требование неадекватное.
А вот изменение имени пользователя спустя секунду после создания — очень даже адекватно.
P>>Если ваш бизнес аналиитк затребовал вообще всё такое — то вы приплыли. ·>Я не в курсе что такое "паблик кей спейса юзера".
public ssl key — ничего военного. Пересоздавать этот кей спустя секунду после создания занятие абсолютно бессмысленное. А вас послушать, так окажется что любые данные ассоциированые с пользователем могут меняться сразу же, включая гуиды ссылок на любую глубину связности.
P>>·>Где находим? Как проверяем? Когда проверяем? P>>Извините, но вам стоит читать внимательнее. Я последее время слишком часто цитирую самого себя. Не можете удерживать контекст — чего вам неймется, "в интернете ктото неправ"? ·>Ты ни разу не ответил прямо на этот вопрос.
Цитирую себя N+1й и N+2q разы
п1 — паттерн тестируется на бд, далее — интеграционными тестами
...
1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
Я вот почему то уверен, что несмотря на эти цитаты вы еще месяц или два будете мне доказывать, что я тестирую только юнит-тестами.
P>>Все код был даден, отмотайте и посмотрите, это всё та же структурная эквивалентность запроса к бд. ·>Мы рассмотрели этот пример, ты вроде даже признал, что там лажа.
Пример недостаточно информативный. А вот сам подход — проверять построение запроса — очень даже хороший.
P>>маппер — по json строит конкретный запрос, createUser P>>паттерн — основа этого запроса ·>что за основа? Запроса какого? sql?
Какого угодно. Если вам для запроса данных нужна цепочка джойнов или вложеный запрос — то это и есть паттерн. А дальше наш билдер должен гарантировать, что для любых возможных параметров, а не только тех, что вы косвенно подкинули в тестах, запрос будет соответствовать заданному паттерно — цепочка джойнов, вложеный запрос, итд итд итд.
А так же надо учесть вещи вида "не делает то чего делать не должен".
P>>трансформация — часть маппера, трансформируем json в нужный нам вид, на выходе — делаем обратное преобразование., ·>Трансформация? Обратная? А что такое transformations? out:...? Это было частью pattern в твоём сниппете. Тут ты говоришь, что это часть маппера.
Путаница из за того, что есть паттерн запроса и паттерн в тесте это похожее, но разное
Вот смотрите
Все что передается в eq — паттерн для теста. А ' наш конкретный запрос' тут проверяем паттерн запроса к бд. Синклер говорит, что эффективнее AST. Это конечно же так. Только пилить АСТ под частный случай я не вижу смысла, во первых. А во вторых, по похожей схеме мы можем проверять запросы любого вида http, rest, rpc, graphql, odata итд.
Например, для эластика у вас будет обычный http запрос.
Можно точно так же проверять запросы к ORM. Это решает проблемы с джигитам "я быстренько, там всё просто"
P>>Я вам продолжаю приводить тот же самый пример — фильтры, когда из за ошибки в построении запроса вгружается вся бд. Вы его усиленно игнорируете. ·>Я не игнорирую, я уже где-то месяц назад написал как его покрыть нормальным тестом. Это ты игнорируешь мои ответы.
Вы показали примитивные тесты вида "положили в таблицу, проверили, что нашли положенное". А как протестировать "не нашли неположенного" или "не начали вгружать вообще всё" — вы такого не показали.
И то, и другое вашими примитивными тестами не решается.
Частично можно решить на боевой бд или приравненой к ней, но только для тех данных что есть сейчас. Как это сделать для тех данных, что у нас будут через год — загадка.
·>Он выполняется косвенно, через кучу слоёв: "когда у нас дошла очередь интеграционного тестирования, где (медленно!) тащатся реальные данные из реальной базы, выполняется (медленный!) UI workflow с навигацией от логина до этого отчёта, и т.п.". ·>Т.е. либо у тебя такие тесты будут гонятся неделями, либо ты сможешь покрыть только ничтожную долю комбинаций этих конкретных запросов. ·>В моём случае тесты выполняют только связку репо+бд и там можно гонять на порядки больше комбинаций.
Связка репо+бд называется интеграционный тест. Вы такими тестами собираетесь покрывать все комбинации
И щас же будете рассказывать, что вы имели в виду чтото другое.
Сколько бы вы комбинаций не всунули в репо+бд тесты — Data Complexity вам такими тестами не сбороть, ну никак.
Но вы продолжаете это пытаться.
Интеграционные нужны для проверки, что репо умеет работать с бд, а вовсе не для проверок комбинаций. Для проверок комбинаций есть другие методы, гораздо более эффективные.
P>>А раз покрыть все комбинации не получится, то незачем и пытаться — нужно переложить критические кейсы на другие методы. ·>Вот и неясно зачем вы пытаетесь это перекладывать на эти ваши странные бесполезные тесты, т.к. нужно другие методы использовать.
Вы только что "показали" — для проверок комбинций использовать интеграционный тест репо+бд
P>>И как вы протестируете, что у вас невозможна ситуация, что прод вгружает вообще всё? ·>Вы тоже не можете это _протестировать_. Просто ещё этого не поняли.
Могу. Например, для тестов которые тянут больше одной строки могу просто затребовать `LIMIT 10`.
P>>·>Именно, для этого и нужны тесты репо+бд. А при наличии таких тестов писать тесты ещё и на построение запросов — неясно зачем. P>>Я ж вам говорил — некорректный запрос в тестах может выдавать корректный результат. И примеры привел. ·>Я примеров не видел. Я видел "объяснения".
Мы уже проходили — код всегда частный случай, на что у вас железный аргумент "у нас такой проблемы быть не может принципиально"
P>>Валидность вообще всех запросов проверить не выйдет — та самая data complexity. Зато можно проверить известные проблемы для тех случаев, когда точная комбинация входа неизвестна. ·>Как? Ты это Проблему Останова решил тестами?
Не я, а вы. Это у вас комбинации покрываются repo+db тестами. А мне достаточно гарантировать наличие свойства запроса. см пример с LIMIT 10 выше. И это свойство сохранится на все времена, а потому проблема останова для меня здесь неактуальна.
·>Ложная альтернатива. Ты "забыл" вариант: гонять через базу все возможные кейсы что есть в бд прода, или нам известно, что такие будут.
Скажите честно, сколько уникальных тестов у вас всего в проекте, всех уровней, видов, итд? И сколько у вас таблиц и связей в бд?
Моя оценка — уникальных тестов у вас самое большее 1000 помножить на число девелоперов. А тестов "комбинаций" из этого будет от силы 1%.
Итого — сколько тестов , таблиц, связей?р
P>>·>Я до сих пор не понимаю почему у тебя есть проблема с загрузкой всей бд в память, решается же элементарно. P>>Вы до сих пор не показали решения. Комбинация параметров вам неизвестна. Действуйте. ·>Только после вас.
Я уже привел кучу примеров. А вы всё никак.
P>>В зависимости от задачи. Например — двойная фильтрация. Часть фильтров в самом запросе, ограничивают выборку, не параметризуются, часть — параметры для фильтрации оставшегося. P>>Теперь что бы вы не подкидывали в фильтр, у вас никогда не будет кейса "вгрузить всё" ·>И что ты будешь ассертить в твоём тесте? sql.contains("LIMIT 1000")?
Зачем contains ? Проверяться будет весь паттерн запроса, а не его фрагмент.
P>>Это именно ваш подход — записать три значения в бд и надеяться что этого хватит. А как протестировать "запрос не тащит откуда не надо" вы не показали. ·>Показал. Запрос должен из условных трёх записей выбирать только условно две.
Не работает. Фильтры могут тащить из херовой тучи таблиц, связей итд. Вам надо самое меньшее — заполнение всех возможных данных, таблиц, связей и тд. И так на каждый тест.
У вас здесь сложность растет экспоненциально.
P>>Вы дурака валяете? deep.eq.pattern это тест для п2. Тесты для п1 — обычные интеграционные. ·>Я читаю что написано.
Ну сейчас то понятно, что интеграционные никто не отменял, или еще месяц-два будете это игнорировать?
P>>По числу юз кейсов. Все юз кейсы должны быть покрыты интеграционными тестами. ·>Давай цифири приведу. В типичном проекте какие мне доводилось наблюдать таких юзкекйсов порядка 100k при более-менее хорошо организованном тестировании. Каждый интеграционный тест вида "...UI workflow с навигацией от логина..." это порядка нескольких секунд, даже без учёта разворачивания и подготовки инфры. Прикинь сколько будет занимать прогон всех таких тестов. В реальности интеграцией можно покрыть от силы 1% кейсов. Если это, конечно, не хоумпейдж.
100к юзкейсов протестировать сложно, а написать легко? Чтото тут не сходится. Вы вероятно юзкейсом называете просто разные варианты параметров для одного и того же вызова контроллера.
P>>На каждую комбинацию накидать минимальную бд — уже мало реально. ·>Я тебе уже объяснял. Не надо накидывать бд на каждую комбинацию. Какие-то жалкие 30 (тридцать!) записей можно фильтровать миллиардом (230) уникальных способов, без учёта сортироваки.
Похоже, вы точно не понимаете data complexity.
Эти 30 комбинаций разложить по таблицам и колонкам и окажется в среднем около нуля на большинстве комбинаций фильров.
P>>Т.е. каждая комбинация это тесты вида "тащим откуда надо" + тесты вида "не тащим откуда не надо" коих много больше. ·>Не так, а так: для комбинации X выбираем эти 7 записей из 30.
См выше — вы разложили 30 записей по таблицами и колонкам и в большинстве случаев у вас выходит 0 значений. А потому 7 из 30 это ни о чем.
Соответственно, пускаете фильтр на проде, и приложение вгружает базу целиком.
Здравствуйте, Sinclair, Вы писали:
S>>>Такие вещи ловятся интеграционным тестированием, которое один хрен нужно проводить. S>·>А что ты в таком тесте, зависящем от DateTime.now() (и ещё пачки внешних зависимостей в неизвестном тесту состоянии) будешь ассертить? Ведь каждый раз у тебя будут выдаваться потенциально совершенно разные результаты. Ну выдался отчёт с 0 строк — тест пройден или как? S>Смотря чего мы ожидали. S>Например, мы точно знаем, как должен выглядеть отчёт за 2023 год — ведь прошлое не меняется. Запускаем, сверяем. S>Ничего "потенциально разного" тут не будет, т.к. речь идёт об интеграции с боевой системой, и там мусора не бывает. S>Либо мы сверяем интеграцию с Test-In-Production — боевой системой, на которой можно экспериментировать бесплатно. S>Тогда интеграционный тест — это прогонка полного цикла типа "создать клиента — зарегистрировать пользователей — выполнить ряд заказов — проверить результаты"
В общем да, при удачном стечении обстоятельств такой подход может и сработает. Но тут столько вещей может пойти не так, притом совершенно ВНЕЗАПНО, что на хоть сколько-то надёжный и универсальный подход никак не тянет.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Pauel, Вы писали:
P>·>Действительно. Какой смысл искать верное решение задачи, если в предыдущем были ошибки. Отличная логика! P>Вы пока ошибок не показали. Основная ваша придирка в том, что структурная эквивалентность не нужна, хрупкая, итд — при этом альтернативы такому решению у вас нет.
Это и есть ошибка. Плюс показал потенциальные ошибки например с дефолтным значением vs null. Альтернативу тоже показал. Просто ты проигнорировал.
P>>>Очень просто — редактироавние после записи нужно для конкретных целей, например — что бы администратор мог подправить свойства только что созданного юзера, а не ждать пять минут. P>·>Это вроде очевидное требование. Необходимость пользователям ждать по пять минут перед тем как нажать кнопочку — должно быть серьёзно обоснованно и обговорено с заказчиком. Как ты это вообще представляешь? P>Вы снова с колокольни? Ничего ждать не надо — в том то и особенность. И всё работает. Потому как данные по пользователю делятся на две большие части — те, что нужны сейчас, и те, что просто нужны. P>Вот например — под нового сотрудника аккаунт создаётся заранее. Здесь заботиться о том, что бы всё-всё-всё(и все гуиды редактировали руками, ага) было доступно к редактированию через 50мс — требование неадекватное. P>А вот изменение имени пользователя спустя секунду после создания — очень даже адекватно.
Ты путаешься в показаниях. Ты сам-то адекватен? Откуда взялось "50мс"??! Ты тут сказал, что синхронное сохранение внезапно заменил на асинхронное и у тебя возникли проблемы с тем, что теперь другой метод можно позвать только через 5 минут. Хуже того, асинхронное вообще не обещает, что оно таки когда-либо произойдёт, а не выпадет какая-нибудь ошибка, которую теперь надо как-то отображать.
P>>>Если ваш бизнес аналиитк затребовал вообще всё такое — то вы приплыли. P>·>Я не в курсе что такое "паблик кей спейса юзера". P>public ssl key — ничего военного. Пересоздавать этот кей спустя секунду после создания занятие абсолютно бессмысленное. А вас послушать, так окажется что любые данные ассоциированые с пользователем могут меняться сразу же, включая гуиды ссылок на любую глубину связности.
Я не знаю что это и какое это всё имеет отношение к обсуждаемому.
P>·>Ты ни разу не ответил прямо на этот вопрос. P>Цитирую себя N+1й и N+2q разы P>
P>п1 — паттерн тестируется на бд, далее — интеграционными тестами
P>...
P>1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
P>Я вот почему то уверен, что несмотря на эти цитаты вы еще месяц или два будете мне доказывать, что я тестирую только юнит-тестами.
Ты пишешь бред. Я задаю вопрос, ты игнорируешь и снова повторяешь то же самое. Попробуем ещё раз:
Я читаю что написано. В цитате выше написано "тестируется" (само как-то?), потом стоит запятая и слово "далее" и про интеграционные тесты. Если эта твоя цитата не говорит что ты хочешь сказать, переформулируй, у меня очень плохо с телепатией.
P>>>Все код был даден, отмотайте и посмотрите, это всё та же структурная эквивалентность запроса к бд. P>·>Мы рассмотрели этот пример, ты вроде даже признал, что там лажа. P>Пример недостаточно информативный. А вот сам подход — проверять построение запроса — очень даже хороший.
Т.е. код не был даден. ЧТД. Куда отматывать-то?
P>·>что за основа? Запроса какого? sql? P>Какого угодно. Если вам для запроса данных нужна цепочка джойнов или вложеный запрос — то это и есть паттерн.
Это ты цель со средством путаешь. Мне надо чтобы запрос выдавал результат который нужен по спеке. А что там — цепочка джойнов или чёрт лысый — абсолютно пофиг. Более того, если сегодня написали запрос с джойнами, а завтра, после разговора с dba его переписали на вложенный — то ни один тест упасть не должен.
P>А дальше наш билдер должен гарантировать, что для любых возможных параметров, а не только тех, что вы косвенно подкинули в тестах, запрос будет соответствовать заданному паттерно — цепочка джойнов, вложеный запрос, итд итд итд. P>А так же надо учесть вещи вида "не делает то чего делать не должен".
Мы говорим о тестах. Как тебе тесты помогут что-то гарантировать? Причём тут тесты??!
P>>>трансформация — часть маппера, трансформируем json в нужный нам вид, на выходе — делаем обратное преобразование., P>·>Трансформация? Обратная? А что такое transformations? out:...? Это было частью pattern в твоём сниппете. Тут ты говоришь, что это часть маппера.
P>Путаница из за того, что есть паттерн запроса и паттерн в тесте это похожее, но разное P>Вот смотрите P>
P>Все что передается в eq — паттерн для теста. А ' наш конкретный запрос' тут проверяем паттерн запроса к бд.
Здесь в коде это просто строка полного sql-запроса, которая сравнивается по equals. Я не понимаю почему ты это называешь паттерном, что в тут паттернится-то?
P>Синклер говорит, что эффективнее AST. Это конечно же так. Только пилить АСТ под частный случай я не вижу смысла, во первых. А во вторых, по похожей схеме мы можем проверять запросы любого вида http, rest, rpc, graphql, odata итд. P>Например, для эластика у вас будет обычный http запрос. P>Можно точно так же проверять запросы к ORM. Это решает проблемы с джигитам "я быстренько, там всё просто"
Ясно. Так я код с такими "паттернами" пишу как раз когда надо "я быстренько, там всё просто". В серьёзных ситуациях за такое надо бить по рукам.
P>>>Я вам продолжаю приводить тот же самый пример — фильтры, когда из за ошибки в построении запроса вгружается вся бд. Вы его усиленно игнорируете. P>·>Я не игнорирую, я уже где-то месяц назад написал как его покрыть нормальным тестом. Это ты игнорируешь мои ответы. P>Вы показали примитивные тесты вида "положили в таблицу, проверили, что нашли положенное". А как протестировать "не нашли неположенного" или "не начали вгружать вообще всё" — вы такого не показали.
Показал. Ещё раз разжую. Минимальный пример: Если мы в таблицу кладём "Vasya", то при поиске, например по шаблону по startsWith("Vas") — должны найти одну запись, а по startsWith("Vaz") — ноль. Второй тест как раз и ассертит, что твой этот фильтр не вгружает всё, а только то, что должно было заматчиться. Ещё раз. Одна запись в БД — это 21 вариантов результата, которые можно различить.
P>И то, и другое вашими примитивными тестами не решается.
Решается.
P>Частично можно решить на боевой бд или приравненой к ней, но только для тех данных что есть сейчас. Как это сделать для тех данных, что у нас будут через год — загадка.
Ты же уже сам привёл ответ на эту загадку: "все возможные кейсы что есть в бд прода, или нам известно, что такие будут".
P>·>Он выполняется косвенно, через кучу слоёв: "когда у нас дошла очередь интеграционного тестирования, где (медленно!) тащатся реальные данные из реальной базы, выполняется (медленный!) UI workflow с навигацией от логина до этого отчёта, и т.п.". P>·>Т.е. либо у тебя такие тесты будут гонятся неделями, либо ты сможешь покрыть только ничтожную долю комбинаций этих конкретных запросов. P>·>В моём случае тесты выполняют только связку репо+бд и там можно гонять на порядки больше комбинаций. P>Связка репо+бд называется интеграционный тест. Вы такими тестами собираетесь покрывать все комбинации
Совершенно похрен как оно называется. Я говорю конкретно что с чем тестируется и как.
P>И щас же будете рассказывать, что вы имели в виду чтото другое.
Я имел в виду ровно то, что написал. Если что-то неясно, перечитай.
P>Сколько бы вы комбинаций не всунули в репо+бд тесты — Data Complexity вам такими тестами не сбороть, ну никак. P>Но вы продолжаете это пытаться.
P>Интеграционные нужны для проверки, что репо умеет работать с бд, а вовсе не для проверок комбинаций. Для проверок комбинаций есть другие методы, гораздо более эффективные.
Что значит "умеет работать"?
P>>>А раз покрыть все комбинации не получится, то незачем и пытаться — нужно переложить критические кейсы на другие методы. P>·>Вот и неясно зачем вы пытаетесь это перекладывать на эти ваши странные бесполезные тесты, т.к. нужно другие методы использовать. P>Вы только что "показали" — для проверок комбинций использовать интеграционный тест репо+бд
Почему нет-то?
P>>>И как вы протестируете, что у вас невозможна ситуация, что прод вгружает вообще всё? P>·>Вы тоже не можете это _протестировать_. Просто ещё этого не поняли. P>Могу. Например, для тестов которые тянут больше одной строки могу просто затребовать `LIMIT 10`.
Как?
P>>>·>Именно, для этого и нужны тесты репо+бд. А при наличии таких тестов писать тесты ещё и на построение запросов — неясно зачем. P>>>Я ж вам говорил — некорректный запрос в тестах может выдавать корректный результат. И примеры привел. P>·>Я примеров не видел. Я видел "объяснения". P>Мы уже проходили — код всегда частный случай, на что у вас железный аргумент "у нас такой проблемы быть не может принципиально"
Код — это формальный язык. По нему сразу видно все ошибки. То что ты стесняешься написать формально — означает, что у тебя из аргументов только словоблудие, на ходу меняешь смысл терминов.
P>>>Валидность вообще всех запросов проверить не выйдет — та самая data complexity. Зато можно проверить известные проблемы для тех случаев, когда точная комбинация входа неизвестна. P>·>Как? Ты это Проблему Останова решил тестами? P>Не я, а вы. Это у вас комбинации покрываются repo+db тестами. А мне достаточно гарантировать наличие свойства запроса. см пример с LIMIT 10 выше. И это свойство сохранится на все времена, а потому проблема останова для меня здесь неактуальна.
Гарантировать наличие любого нетривиального свойства у кода (а запрос — это код) — алгоритмически неразрешимая задача (т. Райса), значит тесты тут никоим образом не помогут.
P>·>Ложная альтернатива. Ты "забыл" вариант: гонять через базу все возможные кейсы что есть в бд прода, или нам известно, что такие будут. P>Скажите честно, сколько уникальных тестов у вас всего в проекте, всех уровней, видов, итд? И сколько у вас таблиц и связей в бд? P>Моя оценка — уникальных тестов у вас самое большее 1000 помножить на число девелоперов. А тестов "комбинаций" из этого будет от силы 1%. P>Итого — сколько тестов , таблиц, связей?р
Цифры я ниже привёл. Базы мелкие, да, ну может порядка сотни таблиц.
P>>>·>Я до сих пор не понимаю почему у тебя есть проблема с загрузкой всей бд в память, решается же элементарно. P>>>Вы до сих пор не показали решения. Комбинация параметров вам неизвестна. Действуйте. P>·>Только после вас. P>Я уже привел кучу примеров. А вы всё никак.
Нигде не было неизвестных комбинаций параметров, не ври.
P>·>И что ты будешь ассертить в твоём тесте? sql.contains("LIMIT 1000")? P>Зачем contains ? Проверяться будет весь паттерн запроса, а не его фрагмент.
Как именно?
P>>>Это именно ваш подход — записать три значения в бд и надеяться что этого хватит. А как протестировать "запрос не тащит откуда не надо" вы не показали. P>·>Показал. Запрос должен из условных трёх записей выбирать только условно две. P>Не работает. Фильтры могут тащить из херовой тучи таблиц, связей итд. Вам надо самое меньшее — заполнение всех возможных данных, таблиц, связей и тд. И так на каждый тест.
Работает. И не на каждый тест, а на прогон практически всех тестов.
P>У вас здесь сложность растет экспоненциально.
Не растёт.
P>>>Вы дурака валяете? deep.eq.pattern это тест для п2. Тесты для п1 — обычные интеграционные. P>·>Я читаю что написано. P>Ну сейчас то понятно, что интеграционные никто не отменял, или еще месяц-два будете это игнорировать?
Я задал вопрос. Ты его удалил не ответив.
P>·>Давай цифири приведу. В типичном проекте какие мне доводилось наблюдать таких юзкекйсов порядка 100k при более-менее хорошо организованном тестировании. Каждый интеграционный тест вида "...UI workflow с навигацией от логина..." это порядка нескольких секунд, даже без учёта разворачивания и подготовки инфры. Прикинь сколько будет занимать прогон всех таких тестов. В реальности интеграцией можно покрыть от силы 1% кейсов. Если это, конечно, не хоумпейдж. P>100к юзкейсов протестировать сложно, а написать легко? Чтото тут не сходится.
Ты откуда нателепатировал "сложно/легко"? Я написал про скорость прогона тестов.
P> Вы вероятно юзкейсом называете просто разные варианты параметров для одного и того же вызова контроллера.
Юзкейс — это в первом приближении кусочек спеки из бизнес-требования, одна хотелка заказчика.
P>>>На каждую комбинацию накидать минимальную бд — уже мало реально. P>·>Я тебе уже объяснял. Не надо накидывать бд на каждую комбинацию. Какие-то жалкие 30 (тридцать!) записей можно фильтровать миллиардом (230) уникальных способов, без учёта сортироваки. P>Похоже, вы точно не понимаете data complexity. P>Эти 30 комбинаций разложить по таблицам и колонкам и окажется в среднем около нуля на большинстве комбинаций фильров.
Почему так окажется? "все возможные кейсы что есть в бд прода, или нам известно, что такие будут.", т.е. раскладываются различные с т.з. бизнеса сущности, а не просто "Account 1", "Account 2".
P>>>Т.е. каждая комбинация это тесты вида "тащим откуда надо" + тесты вида "не тащим откуда не надо" коих много больше. P>·>Не так, а так: для комбинации X выбираем эти 7 записей из 30. P>См выше — вы разложили 30 записей по таблицами и колонкам и в большинстве случаев у вас выходит 0 значений. А потому 7 из 30 это ни о чем. P>Соответственно, пускаете фильтр на проде, и приложение вгружает базу целиком.
Бред.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Вспомнил ваше утверждение про покрытие интеграционными тестами. Смотрите, что вы пишете в очередной раз: > В реальности интеграцией можно покрыть от силы 1% кейсов.
Помните? Вот здесь вы написали обоснование тем самым тестам на проде. Оставшиеся 99% ваши моки не заткнут, как бы вы не старались. Хоть обпишитесь. И даже если вы обмажетесь всеми возможными юнит-тестами, моками, какими угодно — покрытие интеграционными тестами в 1% говорит о том, что за продом нужно наблюдать более серьезными методами, нежели ваши health check.
Для этого подходят e2e тесты — один такой тест может затронуть чуть не половину всех юзкейсов в приложении.
Если же вы хотите заткнуть 99% непокрытых юзкейсов мониторингом на основе с healthcheck — чтото здесь не сходится.
P>>·>Действительно. Какой смысл искать верное решение задачи, если в предыдущем были ошибки. Отличная логика! P>>Вы пока ошибок не показали. Основная ваша придирка в том, что структурная эквивалентность не нужна, хрупкая, итд — при этом альтернативы такому решению у вас нет. ·>Это и есть ошибка. Плюс показал потенциальные ошибки например с дефолтным значением vs null. Альтернативу тоже показал. Происто ты проигнорировал.
Вы показали теоретически возможные ошибки при построении запроса "а вдруг не учтем дефолтное значение". Ну так это и у вас будет — если чего то не учтете.
Ваша альтернатива не работает — упираемся в конское количество колонок, связей и разнообразия свойств внутри джсона — так вот всё хранится.
И ваш подход к тестированию фильтров не палит.
P>>А вот изменение имени пользователя спустя секунду после создания — очень даже адекватно. ·>Ты путаешься в показаниях. Ты сам-то адекватен? Откуда взялось "50мс"??! Ты тут сказал, что синхронное сохранение внезапно заменил на асинхронное и у тебя возникли проблемы с тем, что теперь другой метод можно позвать только через 5 минут.
Я такого не говорил — это вы начали фантазировать, что придется ждать 5 минут и никак иначе не выйдет. Обоснования у вас никакого нет.
P>>public ssl key — ничего военного. Пересоздавать этот кей спустя секунду после создания занятие абсолютно бессмысленное. А вас послушать, так окажется что любые данные ассоциированые с пользователем могут меняться сразу же, включая гуиды ссылок на любую глубину связности. ·>Я не знаю что это и какое это всё имеет отношение к обсуждаемому.
Я вам привел пример, что данные разделяются на те, что нужны сейчас, и те, что нужны потом, когда нибудь. Так не бывает, что всё всегда нужно сразу на любую глубину вложенности.
Если у вас хватает капасити обработать всё за один реквест — отлично. Самый простой вариант, без какого либо усложения архитектуры.
Как только вашего капасити перестает хватать — см требованиия, там написано, что из данных юзера нужно сразу, а что нет.
P>>Я вот почему то уверен, что несмотря на эти цитаты вы еще месяц или два будете мне доказывать, что я тестирую только юнит-тестами. ·>Ты пишешь бред. Я задаю вопрос, ты игнорируешь и снова повторяешь то же самое. Попробуем ещё раз: ·>Я читаю что написано. В цитате выше написано "тестируется" (само как-то?), потом стоит запятая и слово "далее" и про интеграционные тесты. Если эта твоя цитата не говорит что ты хочешь сказать, переформулируй, у меня очень плохо с телепатией.
Цитирую себя N+3й и N+4й разы — выделил
п1 — паттерн тестируется на бд, далее — интеграционными тестами
...
1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
P>>Пример недостаточно информативный. А вот сам подход — проверять построение запроса — очень даже хороший. ·>Т.е. код не был даден. ЧТД. Куда отматывать-то?
Структурная эквивалентность запроса — все что надо, было показано. Вам десяток страниц кода билдера фильтров показать или что?
P>>Какого угодно. Если вам для запроса данных нужна цепочка джойнов или вложеный запрос — то это и есть паттерн. ·>Это ты цель со средством путаешь. Мне надо чтобы запрос выдавал результат который нужен по спеке. А что там — цепочка джойнов или чёрт лысый — абсолютно пофиг. Более того, если сегодня написали запрос с джойнами, а завтра, после разговора с dba его переписали на вложенный — то ни один тест упасть не должен.
Я ж вам сразу сказал — такой тест более хрупкий. Его нужно применять ради решения конкретных проблем, а не лепить вообще везде. Одна из проблема — те самые фильтры.
P>>А так же надо учесть вещи вида "не делает то чего делать не должен". ·>Мы говорим о тестах. Как тебе тесты помогут что-то гарантировать? Причём тут тесты??!
Тесты пишутся именно ради гарантий:
1 делает что надо
2 не делает того, чего не надо
P>>Все что передается в eq — паттерн для теста. А ' наш конкретный запрос' тут проверяем паттерн запроса к бд. ·>Здесь в коде это просто строка полного sql-запроса, которая сравнивается по equals. Я не понимаю почему ты это называешь паттерном, что в тут паттернится-то?
Паттерн — потому, что название даётся по назначению. Назначение этого подхода — проверять построеный запрос на соответствие паттерну.
Если у вас есть более эффективный вариант, например, json-like или AST на алгебраических типах данных, будет еще лучше
P>>Например, для эластика у вас будет обычный http запрос. P>>Можно точно так же проверять запросы к ORM. Это решает проблемы с джигитам "я быстренько, там всё просто" ·>Ясно. Так я код с такими "паттернами" пишу как раз когда надо "я быстренько, там всё просто". В серьёзных ситуациях за такое надо бить по рукам.
Проблема с фильтрами вполне себе серьезная. А вы никак адекватного решения не предложите.
P>>Вы показали примитивные тесты вида "положили в таблицу, проверили, что нашли положенное". А как протестировать "не нашли неположенного" или "не начали вгружать вообще всё" — вы такого не показали. ·>Показал. Ещё раз разжую. Минимальный пример: Если мы в таблицу кладём "Vasya", то при поиске, например по шаблону по startsWith("Vas") — должны найти одну запись, а по startsWith("Vaz") — ноль. Второй тест как раз и ассертит, что твой этот фильтр не вгружает всё, а только то, что должно было заматчиться. Ещё раз. Одна запись в БД — это 21 вариантов результата, которые можно различить.
Очень смешно. Как ваш пример экстраполировать на полторы сотни свойств разного рода — колонки, свойства внутри джсон колонокк, таблиц которые могут джойнами подтягиваться?
Вы ранее говорили — 30 значений положить в бд. Это значит, что 120 свойств будут незаполнеными, и мы не узнаем или ваш запрос фильтрует, или же хавает пустые значения которые в проде окажутся непустыми.
P>>И то, и другое вашими примитивными тестами не решается. ·>Решается.
Нисколько. Если вы положили в таблицу Vasya, то к нему нужно подкинуть полторы сотни так или иначе связанных с ним свойств. Не 30, как вам кажется, а минимум 150. И желательно, что бы таких васей было больше одного.
Фильтр будет не startwith, а
1. конское количество условий — приоритеты, скобки
2. паттерны строк что само по себе хороший цирк
3. джойны в зависимости от условий итд
4. приседания с джсон разной структуры
5. группировки, агрегирование, итд
Например — найти всех вась которые между июнем и июлем делали повторные возвраты товаров из перечня которые были куплены между январем и мартом оформлены менеджерами которые были наняты не позже декабря прошлого года и получив % от сделок уволились с августа по сентябрь
Еще интереснее — найти все товары, которые двигались во всей этой кунсткамере.
P>>Интеграционные нужны для проверки, что репо умеет работать с бд, а вовсе не для проверок комбинаций. Для проверок комбинаций есть другие методы, гораздо более эффективные. ·>Что значит "умеет работать"?
Например, репозиторий Users метод create — параметры — данные юзера, возвращаемое значение — созданный юзер + ассоциированные данные. Нас интересует
1. разложит данные юзера в соответствии со схемой, подкинет гуид где надо
2. построит запрос один или несколько, сколько надо для той бд-сервиса-итд, что в конфигурации
3. отшлет вбд и вернет данные с запрошеными ассоциациями, иды, гуиды — будут соответсвовать схеме, входным данным итд
4. подклеит метадату
5. повторый запрос с тем же гуид должен зафейлиться с конкретной ошибкой
6. такой же запрос с другим гуид должен выполнится хорошо
7. корректно пробрасывать ошибки вида "дисконнект бд из за рестарта"
8. сумеет в опции — ничего не тащить из бд если был флаг write-only
Вот такие вещи показывают интеграцию. Это если вы сами пишете репозиторий, а не берете его готовым в ОРМ фремворке.
Тесты на фильтры здесь минимальные — есть, нету, т.к. нам надо что репозиторий их строит и отдаёт в бд.
А вот всё множество комбинаций в фильтрах нужно покрывать совсем другими тестами.
P>>Вы только что "показали" — для проверок комбинций использовать интеграционный тест репо+бд ·>Почему нет-то?
Потому, что
1 это медленно
2 вы подкидываете небольшое количество значений. Смотрите пример фильтра с васями, только не ваш, а мой
P>>Могу. Например, для тестов которые тянут больше одной строки могу просто затребовать `LIMIT 10`. ·>Как?
Вот так:
`конский запрос LIMIT 10`
И добавить подобное в тесты всех критических запросов.
Т.е. это просто пост условие, и давать будет ровно те же гарантии.
P>>Мы уже проходили — код всегда частный случай, на что у вас железный аргумент "у нас такой проблемы быть не может принципиально" ·>Код — это формальный язык. По нему сразу видно все ошибки. То что ты стесняешься написать формально — означает, что у тебя из аргументов только словоблудие, на ходу меняешь смысл терминов.
С этим есть сложность — ваш код с тестами фильров, те самые васи, говорит о том, что мы с вами совершенно иначе понимаем data complexity
P>>Не я, а вы. Это у вас комбинации покрываются repo+db тестами. А мне достаточно гарантировать наличие свойства запроса. см пример с LIMIT 10 выше. И это свойство сохранится на все времена, а потому проблема останова для меня здесь неактуальна. ·>Гарантировать наличие любого нетривиального свойства у кода (а запрос — это код) — алгоритмически неразрешимая задача (т. Райса), значит тесты тут никоим образом не помогут.
Теорема Райса про алгоритмы и свойства функций, а не про код.
Забавно, что вы только что сами себе рассказали, почему любые ваши тесты без толку. Только такого рода гарантий тестами вообще никто никогда не ставит.
P>>Я уже привел кучу примеров. А вы всё никак. ·>Нигде не было неизвестных комбинаций параметров, не ври.
Это очевидно — никто не даст вам списка "вот только с этими комбинациями не всё в порядке". Вы будете узнавать о той или иной комбинации после креша на проде.
Поэтому вполне логично добавить пост-условие.
P>>Зачем contains ? Проверяться будет весь паттерн запроса, а не его фрагмент. ·>Как именно?
Вы то помните, то не помните. В данной задаче — просто сравнением sql. Назначение теста — зафиксировать паттерн.
P>>Не работает. Фильтры могут тащить из херовой тучи таблиц, связей итд. Вам надо самое меньшее — заполнение всех возможных данных, таблиц, связей и тд. И так на каждый тест. ·>Работает. И не на каждый тест, а на прогон практически всех тестов.
Т.е. вы уже меняете подход к тестам — изначально у вас было "записать три значения в бд и проверить, что они находятся фильтром"
P>>У вас здесь сложность растет экспоненциально. ·>Не растёт.
Растет. Докинули поле — нужно докинуть данных на все случаи, где это будет играть, включая паттерны строк, джойны, итд итд.
P>>Ну сейчас то понятно, что интеграционные никто не отменял, или еще месяц-два будете это игнорировать? ·>Я задал вопрос. Ты его удалил не ответив.
Цитирую себя N+5й и N+6й разы — выделил
п1 — паттерн тестируется на бд, далее — интеграционными тестами
...
1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
P>>100к юзкейсов протестировать сложно, а написать легко? Чтото тут не сходится. ·>Ты откуда нателепатировал "сложно/легко"? Я написал про скорость прогона тестов.
Вот видите — это у вас времени на тесты не хватает, т.к. логику да комбинации вы чекаете на реальной бд
P>> Вы вероятно юзкейсом называете просто разные варианты параметров для одного и того же вызова контроллера. ·>Юзкейс — это в первом приближении кусочек спеки из бизнес-требования, одна хотелка заказчика.
Вам надо определиться — не то есть тесты, не то нету.Код написан — должны быть тесты. А на комбинации времени не хватает, т.к. через бд гоняете.
P>>Эти 30 комбинаций разложить по таблицам и колонкам и окажется в среднем около нуля на большинстве комбинаций фильров. ·>Почему так окажется? "все возможные кейсы что есть в бд прода, или нам известно, что такие будут.", т.е. раскладываются различные с т.з. бизнеса сущности, а не просто "Account 1", "Account 2".
Здравствуйте, Pauel, Вы писали:
>> В реальности интеграцией можно покрыть от силы 1% кейсов. P>Помните? Вот здесь вы написали обоснование тем самым тестам на проде.
Я здесь писал про интеграционные тесты вида "когда у нас дошла очередь интеграционного тестирования, где (медленно!) тащатся реальные данные из реальной базы, выполняется (медленный!) UI workflow с навигацией от логина до этого отчёта, и т.п.". И 1% тут получается не потому что нам лень покрывать всё на 100%, а потому что эти тесты медленные, т.е. 100% будет требовать в 100 раз больше времени, чем 1%. А с учётом праздников и выходных это означает, что вместо получаса это выльется в неделю.
P>Оставшиеся 99% ваши моки не заткнут, как бы вы не старались. Хоть обпишитесь.
Именно это и есть основное предназначение моков — ускорять процесс тестирования.
P>И даже если вы обмажетесь всеми возможными юнит-тестами, моками, какими угодно — покрытие интеграционными тестами в 1% говорит о том, что за продом нужно наблюдать более серьезными методами, нежели ваши health check. P>Для этого подходят e2e тесты — один такой тест может затронуть чуть не половину всех юзкейсов в приложении.
В хоумпейдж приложении — запросто. В реальном приложениии — всё грустно. Вот взять какой-нибудь FX Options. Есть несколько видов Options: Vanilla, Barrier, Binary, KnockIn/Out, Accumulator, Swap, Buttefly, &c. У каждого вида ещё нескольо вариаций Call/Put, Buy/Sell, Hi/Lo, &c. Потом разница algo/manual прайсинг, потом дюжина вариантов booking. И эти все комбинации — валидные сценарии. Одних таких тестов для разных комбинаций будут сотни. В e2e это будет часами тестироваться. Поэтому и приходится бить на части, мокать зависимости и тестировать по частям. Поэтому e2e тест будет один или около того, только одна конкретная комбинация. "Vanilla Buy Call, Auto Price, Execute, B2B Book -> assert trade reports, assert UI". Все остальные комбинации — должны быть покрыты быстрыми тестами.
P>Если же вы хотите заткнуть 99% непокрытых юзкейсов мониторингом на основе с healthcheck — чтото здесь не сходится.
Ты не понял что делает healthcheck.
P>>>Вы пока ошибок не показали. Основная ваша придирка в том, что структурная эквивалентность не нужна, хрупкая, итд — при этом альтернативы такому решению у вас нет. P>·>Это и есть ошибка. Плюс показал потенциальные ошибки например с дефолтным значением vs null. Альтернативу тоже показал. Происто ты проигнорировал. P>Вы показали теоретически возможные ошибки при построении запроса "а вдруг не учтем дефолтное значение". Ну так это и у вас будет — если чего то не учтете.
Если чего-то не учтёте — та же проблема и у вас. Я говорю о другом. Ты вроде учёл "а что если поле null" — и подставил nullзначение в своём pattern-тесте и прописал ожидания, тест зелёный. Но ты не учёл, что реальная субд null заменяет null на дефолтное значение и ведёт не так как ты предположил в своём тесте. А прогонять полные тесты "где (медленно!) тащатся реальные данные" для каждого поля где потенциально может быть null — ты не дождёшься окончания.
P>Ваша альтернатива не работает — упираемся в конское количество колонок, связей и разнообразия свойств внутри джсона — так вот всё хранится. P>И ваш подход к тестированию фильтров не палит.
Режь слона на части, тогда всё запалит.
P>>>А вот изменение имени пользователя спустя секунду после создания — очень даже адекватно. P>·>Ты путаешься в показаниях. Ты сам-то адекватен? Откуда взялось "50мс"??! Ты тут сказал, что синхронное сохранение внезапно заменил на асинхронное и у тебя возникли проблемы с тем, что теперь другой метод можно позвать только через 5 минут. P>Я такого не говорил — это вы начали фантазировать, что придется ждать 5 минут и никак иначе не выйдет. Обоснования у вас никакого нет.
Про 5 минут я не фантазировал, это твоя цитата.
P>>>public ssl key — ничего военного. Пересоздавать этот кей спустя секунду после создания занятие абсолютно бессмысленное. А вас послушать, так окажется что любые данные ассоциированые с пользователем могут меняться сразу же, включая гуиды ссылок на любую глубину связности. P>·>Я не знаю что это и какое это всё имеет отношение к обсуждаемому. P>Я вам привел пример, что данные разделяются на те, что нужны сейчас, и те, что нужны потом, когда нибудь. Так не бывает, что всё всегда нужно сразу на любую глубину вложенности. P>Если у вас хватает капасити обработать всё за один реквест — отлично. Самый простой вариант, без какого либо усложения архитектуры. P>Как только вашего капасити перестает хватать — см требованиия, там написано, что из данных юзера нужно сразу, а что нет.
Да похрен на архитектуру, главное — это означает, что какие-то операции временно перестанут работать как раньше, меняется happens-before гарантии. Появляется необходимость синхронизации, т.е. функциональное изменение, модификация API, документации и т.п. Тесты ну просто обязаны грохнуться!
P>·>Ты пишешь бред. Я задаю вопрос, ты игнорируешь и снова повторяешь то же самое. Попробуем ещё раз: P>·>Я читаю что написано. В цитате выше написано "тестируется" (само как-то?), потом стоит запятая и слово "далее" и про интеграционные тесты. Если эта твоя цитата не говорит что ты хочешь сказать, переформулируй, у меня очень плохо с телепатией. P>Цитирую себя N+3й и N+4й разы — выделил P>
P>п1 — паттерн тестируется на бд, далее — интеграционными тестами
P>...
P>1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
Я тебе в N+5й раз повторяю. Твоя формулировка неоднозначна. Напиши чётко.
P>>>Пример недостаточно информативный. А вот сам подход — проверять построение запроса — очень даже хороший. P>·>Т.е. код не был даден. ЧТД. Куда отматывать-то? P>Структурная эквивалентность запроса — все что надо, было показано. Вам десяток страниц кода билдера фильтров показать или что?
Было показано deep.eq(..."some string"...), т.е. буквальное, посимвольное сравнение текста sql-запроса. Неясно где какой тут паттерн который ты "объясняешь", но код не показываешь.
P>>>Какого угодно. Если вам для запроса данных нужна цепочка джойнов или вложеный запрос — то это и есть паттерн. P>·>Это ты цель со средством путаешь. Мне надо чтобы запрос выдавал результат который нужен по спеке. А что там — цепочка джойнов или чёрт лысый — абсолютно пофиг. Более того, если сегодня написали запрос с джойнами, а завтра, после разговора с dba его переписали на вложенный — то ни один тест упасть не должен. P>Я ж вам сразу сказал — такой тест более хрупкий.
Не, ты это не говорил. Но не важно...
P>Его нужно применять ради решения конкретных проблем, а не лепить вообще везде. Одна из проблема — те самые фильтры.
...главное — неясно зачем писать такой хрупкий тест, когда можно банально гонять его же на бд, ровно с теми же сценариями и ассертами (ок, может чуть медленнее).
P>>>А так же надо учесть вещи вида "не делает то чего делать не должен". P>·>Мы говорим о тестах. Как тебе тесты помогут что-то гарантировать? Причём тут тесты??! P>Тесты пишутся именно ради гарантий: P>1 делает что надо P>2 не делает того, чего не надо
Так и я показал как учитывать такие вещи в тестах репо+бд.
P>>>Все что передается в eq — паттерн для теста. А ' наш конкретный запрос' тут проверяем паттерн запроса к бд. P>·>Здесь в коде это просто строка полного sql-запроса, которая сравнивается по equals. Я не понимаю почему ты это называешь паттерном, что в тут паттернится-то? P>Паттерн — потому, что название даётся по назначению. Назначение этого подхода — проверять построеный запрос на соответствие паттерну.
Словоблудие.
P>Если у вас есть более эффективный вариант, например, json-like или AST на алгебраических типах данных, будет еще лучше
Как это будет выглядеть в коде?
P>>>Вы показали примитивные тесты вида "положили в таблицу, проверили, что нашли положенное". А как протестировать "не нашли неположенного" или "не начали вгружать вообще всё" — вы такого не показали. P>·>Показал. Ещё раз разжую. Минимальный пример: Если мы в таблицу кладём "Vasya", то при поиске, например по шаблону по startsWith("Vas") — должны найти одну запись, а по startsWith("Vaz") — ноль. Второй тест как раз и ассертит, что твой этот фильтр не вгружает всё, а только то, что должно было заматчиться. Ещё раз. Одна запись в БД — это 21 вариантов результата, которые можно различить. P>Очень смешно. Как ваш пример экстраполировать на полторы сотни свойств разного рода — колонки, свойства внутри джсон колонокк, таблиц которые могут джойнами подтягиваться? P>Вы ранее говорили — 30 значений положить в бд. Это значит, что 120 свойств будут незаполнеными, и мы не узнаем или ваш запрос фильтрует, или же хавает пустые значения которые в проде окажутся непустыми.
Я имею в виду положить 30 записей. Фильтрами потом выбираем из этих 30 и проверяем, что выбраны только те записи, которые должны попадать под данный фильтр. У каждой записи может быть сколь угодно свойств.
P>>>И то, и другое вашими примитивными тестами не решается. P>·>Решается. P> P>Нисколько. Если вы положили в таблицу Vasya, то к нему нужно подкинуть полторы сотни так или иначе связанных с ним свойств. Не 30, как вам кажется, а минимум 150. И желательно, что бы таких васей было больше одного.
Ну да. И? Можешь сформировать как тестовый объект vasya и для него вызвать тот же repo.save(vasya). Т.е. вставляешь 30 вась в базу и фильтруешь их в хвост и гриву.
P>Фильтр будет не startwith, а P>1. конское количество условий — приоритеты, скобки P>2. паттерны строк что само по себе хороший цирк P>3. джойны в зависимости от условий итд P>4. приседания с джсон разной структуры P>5. группировки, агрегирование, итд
Ну это всё ты вроде сказал уже и так будет в твоих паттерн-тестах. Суть в том, что вместо тупого побуквенного сравнения sql-текста, они этот самый sql-текст выполнят на базе из 30и записей и заасертят выданный список.
P>Например — найти всех вась которые между июнем и июлем делали повторные возвраты товаров из перечня которые были куплены между январем и мартом оформлены менеджерами которые были наняты не позже декабря прошлого года и получив % от сделок уволились с августа по сентябрь P>Еще интереснее — найти все товары, которые двигались во всей этой кунсткамере.
И? А ты что предлагаешь? Запустить эту колбасу вручную на прод-базе и глазками проверить выдачу, что вроде похоже на правду?
P>>>Интеграционные нужны для проверки, что репо умеет работать с бд, а вовсе не для проверок комбинаций. Для проверок комбинаций есть другие методы, гораздо более эффективные. P>·>Что значит "умеет работать"? P>Например, репозиторий Users метод create — параметры — данные юзера, возвращаемое значение — созданный юзер + ассоциированные данные. Нас интересует P>1. разложит данные юзера в соответствии со схемой, подкинет гуид где надо P>2. построит запрос один или несколько, сколько надо для той бд-сервиса-итд, что в конфигурации P>3. отшлет вбд и вернет данные с запрошеными ассоциациями, иды, гуиды — будут соответсвовать схеме, входным данным итд P>4. подклеит метадату P>5. повторый запрос с тем же гуид должен зафейлиться с конкретной ошибкой P>6. такой же запрос с другим гуид должен выполнится хорошо P>7. корректно пробрасывать ошибки вида "дисконнект бд из за рестарта" P>8. сумеет в опции — ничего не тащить из бд если был флаг write-only
Давай теперь по каждому из этих пунктов, как это валидируется в твоих интеграционных тестах.
А то вообще, внезапно может случиться так, что в тесте результат подсосался из кеша и до репы вообще дело не долшо?
P>А вот всё множество комбинаций в фильтрах нужно покрывать совсем другими тестами.
Т.е. если одна из комбинаций фильтров нарушит, скажем пункт 8, то ты об этом узнаешь только в проде от счастливых юзеров.
P>>>Вы только что "показали" — для проверок комбинций использовать интеграционный тест репо+бд P>·>Почему нет-то? P>Потому, что P>1 это медленно
Согласен, медленнее, т.к. лезет в бд. Но бд может выполнять тысячи запросов в секунду.
P>2 вы подкидываете небольшое количество значений. Смотрите пример фильтра с васями, только не ваш, а мой
Подкидывай большое число значений. Разрешаю.
P>>>Могу. Например, для тестов которые тянут больше одной строки могу просто затребовать `LIMIT 10`. P>·>Как? P>Вот так: P>`конский запрос LIMIT 10`
Согласен, иногда такое может сработать, не помню как оно себя поведёт с какими-нибудь union... Да ещё и в разных базах этот самый LIMIT может выглядеть по-разному. А как ты будешь отличать "тянут больше одной строки"?
P>И добавить подобное в тесты всех критических запросов. P>Т.е. это просто пост условие, и давать будет ровно те же гарантии.
Неясно как это согласуется с бизнес-требованиями.
P>>>Не я, а вы. Это у вас комбинации покрываются repo+db тестами. А мне достаточно гарантировать наличие свойства запроса. см пример с LIMIT 10 выше. И это свойство сохранится на все времена, а потому проблема останова для меня здесь неактуальна. P>·>Гарантировать наличие любого нетривиального свойства у кода (а запрос — это код) — алгоритмически неразрешимая задача (т. Райса), значит тесты тут никоим образом не помогут. P>Теорема Райса про алгоритмы и свойства функций, а не про код.
— код это один из видов формальной записи алгоритмов. А функции (ты наверно имеешь в виду чрф) эквивалентны алгоритмам по тезису Тьюринга-Чёрча. Ок... С натяжкой можно сказать, что sql не является тьюринг-полным (обычно), поэтому по его коду можно иногда определить его некоторые свойства.
P>Забавно, что вы только что сами себе рассказали, почему любые ваши тесты без толку. Только такого рода гарантий тестами вообще никто никогда не ставит.
Поправил, чтобы верно стало. Я это давно тебе пытаюсь объяснить. Наконец-то ты начал чего-то подозревать.
P>>>Я уже привел кучу примеров. А вы всё никак. P>·>Нигде не было неизвестных комбинаций параметров, не ври. P>Это очевидно — никто не даст вам списка "вот только с этими комбинациями не всё в порядке". Вы будете узнавать о той или иной комбинации после креша на проде. P>Поэтому вполне логично добавить пост-условие.
Ну добавь. Тесты тут не причём. Сразу замечу, что тестировать наличие постусловий — это уже лютейший бред.
P>>>Зачем contains ? Проверяться будет весь паттерн запроса, а не его фрагмент. P>·>Как именно? P>Вы то помните, то не помните. В данной задаче — просто сравнением sql. Назначение теста — зафиксировать паттерн.
Назначение теста — это твои фантазии. Суть теста — это то что он делает по факту. А по факту он сравнивает побуквенно sql, а паттерны запроса и прочие страшные слова — это пустое словоблудие.
P>>>Не работает. Фильтры могут тащить из херовой тучи таблиц, связей итд. Вам надо самое меньшее — заполнение всех возможных данных, таблиц, связей и тд. И так на каждый тест. P>·>Работает. И не на каждый тест, а на прогон практически всех тестов. P>Т.е. вы уже меняете подход к тестам — изначально у вас было "записать три значения в бд и проверить, что они находятся фильтром"
Ты опять врёшь. Вот моя настоящая цитата: "Достаточно иметь одно значение и слать разные фильтры.". Открой мой код и прочитай его ещё раз. Внимательно.
P>>>У вас здесь сложность растет экспоненциально. P>·>Не растёт. P>Растет. Докинули поле — нужно докинуть данных на все случаи, где это будет играть, включая паттерны строк, джойны, итд итд.
Ок, переформулирую. Сложность у нас растёт ровно так же, как и у вас.
P>>>Ну сейчас то понятно, что интеграционные никто не отменял, или еще месяц-два будете это игнорировать? P>·>Я задал вопрос. Ты его удалил не ответив. P>Цитирую себя N+5й и N+6й разы — выделил
Ты написал: "паттерн тестируется на бд, далее — интеграционными тестами". Я спрашиваю: как паттерн тестируется на бд _перед_ интеграционными тестами?
P>1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
Каким именно тестом? Как этот тест выглядит и какой код этот тест покрывает?
P>>>100к юзкейсов протестировать сложно, а написать легко? Чтото тут не сходится. P>·>Ты откуда нателепатировал "сложно/легко"? Я написал про скорость прогона тестов. P>Вот видите — это у вас времени на тесты не хватает, т.к. логику да комбинации вы чекаете на реальной бд
На реальной бд мы чекаем только связку бд+репо, т.е. код персистенса, а не логику и комбинации.
P>>>Эти 30 комбинаций разложить по таблицам и колонкам и окажется в среднем около нуля на большинстве комбинаций фильров. P>·>Почему так окажется? "все возможные кейсы что есть в бд прода, или нам известно, что такие будут.", т.е. раскладываются различные с т.з. бизнеса сущности, а не просто "Account 1", "Account 2". P>У вас комбинаций меньше чем условий в фильтре.
30 это было число записей, которые могут обеспечить 230 комбинаций. Тебе столько не хватает?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
>>> В реальности интеграцией можно покрыть от силы 1% кейсов. P>>Помните? Вот здесь вы написали обоснование тем самым тестам на проде. ·>Я здесь писал про интеграционные тесты вида "когда у нас дошла очередь интеграционного тестирования, где (медленно!) тащатся реальные данные из реальной базы, выполняется (медленный!) UI workflow с навигацией от логина до этого отчёта, и т.п.". И 1% тут получается не потому что нам лень покрывать всё на 100%, а потому что эти тесты медленные, т.е. 100% будет требовать в 100 раз больше времени, чем 1%. А с учётом праздников и выходных это означает, что вместо получаса это выльется в неделю.
Будут. Но их всё равно нужно делать, т.к. никакие другие виды тестов их не заменяют, только кое где могут скомпенсировать.
Например — если логика сложная, а воркфлоу простой, то можно забить на e2e и заложиться на юнит-тесты.
Если у вас сложный воркфлоу, то его нечем протестировать, кроме вот этих e2e
P>>Оставшиеся 99% ваши моки не заткнут, как бы вы не старались. Хоть обпишитесь. ·>Именно это и есть основное предназначение моков — ускорять процесс тестирования.
Вы сейчас снова утверждаете, что моки могут заменять интеграционные.
Не могут — моки по своей сути подменяют интеграцию отсебятиной.
И вы проверяете, что ваш код справляется с этой отсебятиной.
Как он будет справляться с интеграцией — остаётся неизвестным, вообще.
Ответ даёт исключительно прямая проверка этой интеграции
P>>Для этого подходят e2e тесты — один такой тест может затронуть чуть не половину всех юзкейсов в приложении. ·>В хоумпейдж приложении — запросто. В реальном приложениии — всё грустно. Вот взять какой-нибудь FX Options. Есть несколько видов Options: Vanilla, Barrier, Binary, KnockIn/Out, Accumulator, Swap, Buttefly, &c. У каждого вида ещё нескольо вариаций Call/Put, Buy/Sell, Hi/Lo, &c. Потом разница algo/manual прайсинг, потом дюжина вариантов booking. И эти все комбинации — валидные сценарии. Одних таких тестов для разных комбинаций будут сотни. В e2e это будет часами тестироваться. Поэтому и приходится бить на части, мокать зависимости и тестировать по частям.
Итого, с ваших слов "задача сложная, нахер e2e, будем моки писать и сделаем вид, что это равноценная замена"
e2e у вас должен покрывать все ключевые опции, т.к. это разные сценарии.
Еще раз — все.
Если вам непонятно — все означает все.
На случай если вы и здесь игнорите — все.
Вопрос только в том, как вы будете временем распоряжяться.
1 Аксиома — количество юнит-тестов и полуинтеграционных на моках никак не влияет на количество e2e. Никак, нисколько!
юниты и ваши полуинтеграционные пишите сколько надо, что бы быстро детектить мелочевку во время разработки
2 e2e можно сделать так —
— при билде — три самых частых
— при деплое — три десятка самых частых
— после деплоя — всё вместе, рандомно, то одно, то другое, с таким расчетом, что бы за день вы получили сведения что где может отвалиться
Итого — ваши 99% кейсов вы будете тестировать после деплоя. Боитесь делать это на проде — делайте на стейдже, деве и тд.
Как решить:
1. деплоймент, например, стейдж, отдаёт манифест — версия-тег, урл репозитория с тестами конкретной этой версии.
2. e2e тесты умеют запуск рандомного сценария
3. каждые N минут запускаете `curl <stage>/manifest.test | run-test --random --url <stage>`
4. результаты запусков кладете не абы куда, а в репозиторий
5. в каждый момент времени вы можете обновить этот репозиторий и посмотреть состояние всего, что у вас происходит
6. сыплются ошибки — заводятся баги
P>>Если же вы хотите заткнуть 99% непокрытых юзкейсов мониторингом на основе с healthcheck — чтото здесь не сходится. ·>Ты не понял что делает healthcheck.
Это ж не я пытаюсь заменить 99% e2e тестов моками.
P>>Вы показали теоретически возможные ошибки при построении запроса "а вдруг не учтем дефолтное значение". Ну так это и у вас будет — если чего то не учтете. ·>Если чего-то не учтёте — та же проблема и у вас. Я говорю о другом. Ты вроде учёл "а что если поле null" — и подставил nullзначение в своём pattern-тесте и прописал ожидания, тест зелёный. Но ты не учёл, что реальная субд null заменяет null на дефолтное значение и ведёт не так как ты предположил в своём тесте. А прогонять полные тесты "где (медленно!) тащатся реальные данные" для каждого поля где потенциально может быть null — ты не дождёшься окончания.
Это полные тесты, где всё тащится медленно и реально — они нужны и вам, и мне. Если вы не учли этот кейс с нулём, то будет проблема. Ровно так же и у меня.
P>>Ваша альтернатива не работает — упираемся в конское количество колонок, связей и разнообразия свойств внутри джсона — так вот всё хранится. P>>И ваш подход к тестированию фильтров не палит. ·>Режь слона на части, тогда всё запалит.
Не запалит. По частям мы выясним, что каждая часть по отдельности работает. А вот как поведут себя комбинации частей — остаётся неизвестным.
И задача с фильтрами это про комбинации
P>>Я такого не говорил — это вы начали фантазировать, что придется ждать 5 минут и никак иначе не выйдет. Обоснования у вас никакого нет. ·>Про 5 минут я не фантазировал, это твоя цитата.
Я нигде не говорил, что юзер должен ждать 5 минут. Даже если профиль создаётся неделю, редактировать данные можно сразу.
Вам нужно спросить у BA, какие данные надо сейчас, а какие — вообще.
P>>Если у вас хватает капасити обработать всё за один реквест — отлично. Самый простой вариант, без какого либо усложения архитектуры. P>>Как только вашего капасити перестает хватать — см требованиия, там написано, что из данных юзера нужно сразу, а что нет. ·>Да похрен на архитектуру, главное — это означает, что какие-то операции временно перестанут работать как раньше, меняется happens-before гарантии. Появляется необходимость синхронизации, т.е. функциональное изменение, модификация API, документации и т.п. Тесты ну просто обязаны грохнуться!
Вы похоже так и не поняли, что такое функциональные требования, а что такое нефункциональные.
Пример:
Функциональные — админ может создать спейс для юзера, админ может отредактировать профиль юзера.
Нефункциональные — профиль юзера можно редактировать сразу после создания. Профиль юзера создаётся за 100 мсек. админ не должен ждать чего то там.
Вы сами себе придумали какой то вариант, где сделано заведомо кривое решение, и теперь рассказываете будто это самый типичный случай.
На самом деле нет — см функциональные и нефункциональные требования.
Зачем вам менять апишку для этого кейса?
P>>·>Я читаю что написано. В цитате выше написано "тестируется" (само как-то?), потом стоит запятая и слово "далее" и про интеграционные тесты. Если эта твоя цитата не говорит что ты хочешь сказать, переформулируй, у меня очень плохо с телепатией. P>>Цитирую себя N+3й и N+4й разы — выделил P>>
P>>п1 — паттерн тестируется на бд, далее — интеграционными тестами
P>>...
P>>1. рабочий паттерн запроса — это проверяется сначала руками, а потом тестом против бд минимально заполненой под задачу
·>Я тебе в N+5й раз повторяю. Твоя формулировка неоднозначна. Напиши чётко.
Я не в курсе, что именно вам непонятно
Какой вопрос вы не озвочили — мне неизвестно.
На мой взгляд что надо в моем ответе есть
1. кто тестирует
2. на чем тестирует
3. какими тестами
4. какая бд и чем заполнена
Что вам в этом ответе непонятно? Что конкретно? Вы вопрос внятно сформулировать можете или мне за вас это делать четвертый месяц?
P>>Структурная эквивалентность запроса — все что надо, было показано. Вам десяток страниц кода билдера фильтров показать или что? ·>Было показано deep.eq(..."some string"...), т.е. буквальное, посимвольное сравнение текста sql-запроса. Неясно где какой тут паттерн который ты "объясняешь", но код не показываешь.
проверка паттерна посимвольным сравнением
1. что делаем — сравниваем посимвольно, т.к. другого варианта нет — на одну задачу пилить ast на алгебраических типах данных это овердохрена
2. для чего делаем — что бы зафиксировать паттерн
P>>Его нужно применять ради решения конкретных проблем, а не лепить вообще везде. Одна из проблема — те самые фильтры. ·>...главное — неясно зачем писать такой хрупкий тест, когда можно банально гонять его же на бд, ровно с теми же сценариями и ассертами (ок, может чуть медленнее).
Я ж вас попросил — покажите тест, который на неизвестной комбинации фильтров будет гарантировано вгружать в память не более 10 строк.
Вы до сих пор такой тест не показали
P>>Тесты пишутся именно ради гарантий: P>>1 делает что надо P>>2 не делает того, чего не надо ·>Так и я показал как учитывать такие вещи в тестах репо+бд.
Я ж вас попросил — покажите тест, который на неизвестной комбинации фильтров будет гарантировано вгружать в память не более 10 строк.
Вы до сих пор такой тест не показали
P>>Паттерн — потому, что название даётся по назначению. Назначение этого подхода — проверять построеный запрос на соответствие паттерну. ·>Словоблудие.
Вы в который раз просите объяснений, и тут же всё это обесцениваете.
Зачем вы вообще сюда пишете, показать, что у вас адекватных, релевантных аргументов нет, или что "в интернете ктото неправ" ?
P>>Если у вас есть более эффективный вариант, например, json-like или AST на алгебраических типах данных, будет еще лучше ·>Как это будет выглядеть в коде?
В результате этот request вы сможете сравнить с другим, как целиком, так и частично.
Например, у нас здесь простой паттерн — выбрать десять последних с простым фильтром.
Например, для такого паттерна я могу написать тест, который будет ограничивать filterExpression простыми выражениями
Можно ограничить таблицы, из которых может или не может делаться джойн итд
P>>Очень смешно. Как ваш пример экстраполировать на полторы сотни свойств разного рода — колонки, свойства внутри джсон колонокк, таблиц которые могут джойнами подтягиваться? P>>Вы ранее говорили — 30 значений положить в бд. Это значит, что 120 свойств будут незаполнеными, и мы не узнаем или ваш запрос фильтрует, или же хавает пустые значения которые в проде окажутся непустыми. ·>Я имею в виду положить 30 записей. Фильтрами потом выбираем из этих 30 и проверяем, что выбраны только те записи, которые должны попадать под данный фильтр. У каждой записи может быть сколь угодно свойств.
Кто вам скажет, что в ваших этих 30 записях есть все потенциально опасные или невалидные комбинации?
P>>Например — найти всех вась которые между июнем и июлем делали повторные возвраты товаров из перечня которые были куплены между январем и мартом оформлены менеджерами которые были наняты не позже декабря прошлого года и получив % от сделок уволились с августа по сентябрь P>>Еще интереснее — найти все товары, которые двигались во всей этой кунсткамере. ·>И? А ты что предлагаешь? Запустить эту колбасу вручную на прод-базе и глазками проверить выдачу, что вроде похоже на правду?
Вручную всё равно придется проверять, это обязательный этап — с этого всё начинается.
P>>Например, репозиторий Users метод create — параметры — данные юзера, возвращаемое значение — созданный юзер + ассоциированные данные. Нас интересует P>>1. разложит данные юзера в соответствии со схемой, подкинет гуид где надо P>>2. построит запрос один или несколько, сколько надо для той бд-сервиса-итд, что в конфигурации P>>3. отшлет вбд и вернет данные с запрошеными ассоциациями, иды, гуиды — будут соответсвовать схеме, входным данным итд P>>4. подклеит метадату P>>5. повторый запрос с тем же гуид должен зафейлиться с конкретной ошибкой P>>6. такой же запрос с другим гуид должен выполнится хорошо P>>7. корректно пробрасывать ошибки вида "дисконнект бд из за рестарта" P>>8. сумеет в опции — ничего не тащить из бд если был флаг write-only ·>Давай теперь по каждому из этих пунктов, как это валидируется в твоих интеграционных тестах.
Эта часть же как и у вас. Это именно интеграционный тест репозитория.
Только сверх этого вы собираетесь и комбинации фильтров гонять здесь же. И на мой взгляд это совсем не то, чем нужно заниматься в этом виде тестов.
P>>А вот всё множество комбинаций в фильтрах нужно покрывать совсем другими тестами. ·>Т.е. если одна из комбинаций фильтров нарушит, скажем пункт 8, то ты об этом узнаешь только в проде от счастливых юзеров.
А у вас как будет? Сколько процентов комбинаций вам известно и сколько из них вы покрыли интеграционным тестом?
Вы только недавно жаловались, что у вас покрывается внятно только 1% кейсов
Поскольку комбинаций фильтров может быть на порядки больше, чем вы можете позволить себе покрыть тестами, то:
1 подкинули флаг и выхлоп пустой — интеграционный тест, по одному на самые частые паттерны запросов
1. update — возвращаем пусто если write-only, или новое состояние
2. get — кидаем исключение, если write-only
3. итд
2 пост-условие — выхлоп пустой — это не тест, а именно пост-условие. Та часть которая вам непонятна последние 4 месяца
3 логирование — выхлоп игнорируется, если есть, с записью в лог, далее — всплывет в мониторинге при первом же случае.
4 дизайн — пре-, и пост-процессинг определяется маппером, а не набором if. Маппер тестируем юнит тестами.
P>>2 вы подкидываете небольшое количество значений. Смотрите пример фильтра с васями, только не ваш, а мой ·>Подкидывай большое число значений. Разрешаю.
Проблемные комбинации вам неизвестны.
Что будете в тест писать ?
P>>`конский запрос LIMIT 10` ·>Согласен, иногда такое может сработать, не помню как оно себя поведёт с какими-нибудь union... Да ещё и в разных базах этот самый LIMIT может выглядеть по-разному. А как ты будешь отличать "тянут больше одной строки"?
Это же в операции известно, какие данные она возвращает. Если users.byId() то очевидно здесь один. А если users.where — вот тут а хрен его знает
P>>Т.е. это просто пост условие, и давать будет ровно те же гарантии. ·>Неясно как это согласуется с бизнес-требованиями.
У вас что, в требованиях позволено сдыхать при процессинге?
1 Нужно обработать весь объем данных
2 дизайн под обработку частями
3 запросы в соответствии с дизайном
4 тесты запросов на соответствие с дизайном, решает вопрос с "я быстренько, там всё просто"
5 код ревью "не выключил ли кто тесты а б и цэ"
ут. P>>Теорема Райса про алгоритмы и свойства функций, а не про код. ·> — код это один из видов формальной записи алгоритмов.
Если пользоваться вашим пониманием т. Райса, то например тесты это тот алгоритм, которому нужно выяснить наличие свойств у функции system-under-test
И тут мы узнаем... что тестами ничо не сделаешь. Гы-гы.
Как только вам это стало понятно, нужно вспомнить, что тестами вы выражаете свои собственные ожидания. Даже если вы их взяли из спеке — интерпретация все равно ваша собственная, и вы в тестах фиксируете свои ожидания от того, как в каких случаях работет система
Соотвественно, гарантии у вас будут не с т.з. т.Райса, а с т.з. вероятностей
— функция которая проходит тесты по таблице истинности подходит лучше, чем та, которая эти тесты не проходит
P>>Забавно, что вы только что сами себе рассказали, почему любые ваши тесты без толку. Только такого рода гарантий тестами вообще никто никогда не ставит. ·>Поправил, чтобы верно стало. Я это давно тебе пытаюсь объяснить. Наконец-то ты начал чего-то подозревать.
Вам стоило бы почитать Гленфорда Майерса — он объясняет подробно, что к чему, откуда какие гарантии берутся
P>>Поэтому вполне логично добавить пост-условие. ·>Ну добавь. Тесты тут не причём. Сразу замечу, что тестировать наличие постусловий — это уже лютейший бред.
У вас всё бред, чего вы не понимаете
P>>Вы то помните, то не помните. В данной задаче — просто сравнением sql. Назначение теста — зафиксировать паттерн. ·>Назначение теста — это твои фантазии. Суть теста — это то что он делает по факту. А по факту он сравнивает побуквенно sql, а паттерны запроса и прочие страшные слова — это пустое словоблудие.
Давайте проверим. Покажите мне пример, как изменение паттерна, структуры запроса будет зеленым в таком тесте.
P>>Т.е. вы уже меняете подход к тестам — изначально у вас было "записать три значения в бд и проверить, что они находятся фильтром" ·>Ты опять врёшь. Вот моя настоящая цитата: "Достаточно иметь одно значение и слать разные фильтры.". Открой мой код и прочитай его ещё раз. Внимательно.
Это еще слабее тест. С одним значением мы не в курсе, а не вгружает ли ваш фильтр секретные данные каким либо джойном
P>>Растет. Докинули поле — нужно докинуть данных на все случаи, где это будет играть, включая паттерны строк, джойны, итд итд. ·>Ок, переформулирую. Сложность у нас растёт ровно так же, как и у вас.
В том то и дело, что растет экспоненциально.
·>Ты написал: "паттерн тестируется на бд, далее — интеграционными тестами". Я спрашиваю: как паттерн тестируется на бд _перед_ интеграционными тестами?
Первые запуски — руками. Потом автоматизируете и получаете интеграционный тест.
P>>Вот видите — это у вас времени на тесты не хватает, т.к. логику да комбинации вы чекаете на реальной бд ·>На реальной бд мы чекаем только связку бд+репо, т.е. код персистенса, а не логику и комбинации.
Вы совсем недавно собирались все комбинации тестировать, разве нет?
Если нет, то ваши же слова
"если одна из комбинаций фильтров нарушит, скажем пункт 8, то ты об этом узнаешь только в проде от счастливых юзеров."
P>>У вас комбинаций меньше чем условий в фильтре. ·>30 это было число записей, которые могут обеспечить 230 комбинаций. Тебе столько не хватает?
Фильтры дают на десяток порядков больше комбинаций. В этом и проблем