Здравствуйте, Pauel, Вы писали:
P>>>А как убедиться, что все части собраные вместе дают нужный результат?
P>·>smoke tests — как вишенка на торт, но в остальном — проверять две вещи: части работают, части собираются между собой нужным образом.
P>Что это за тесты, кто их выполняет?
CI/CD
P>>>>>Вы сами себя ограбили когда строили вашу пирамиду тестов в виде трапеции — полуинтеграционные на моках + конформанс, которые к вашей системе имеют слабое отношение.
P>>>Причин может быть много. Качество не сводится к тестам. Более того — тесты в обеспечении качества это минорная часть.
P>·>Минорная?! Без тестов обеспечить качество практически невозможно.
P>Минорная — это значит, что есть вещи более важные
P>Если у вас нет хотя бы одного 1..4 никакие тесты вам не помогут, хоть обмажтесь.
А без тестов 1-6 уйдут лесом. Единственное, что может не сразу, но уйдут точно.
P>>>Какая связь e2e и "гонять проверки каждого поля на null" ? e2e это про сценарий, а не прогон по всем комбинациям полей/значений.
P>·>Связь в том, что ты в своих юнит-тестах предлагаешь проверять поля на null, но интеграцию этого же кода с реальной субд — провеять уже через e2e.
P>Похоже, ваш капасити переполнен три месяца назад. Вы здесь, извините, порете отсебятину.
У тебя память как у рыбки. Цитирую:
·>потенциально может быть null — ты не дождёшься окончания.
Это полные тесты, где всё тащится медленно и реально
P>>>e2e много и не нужно.
P>·>Где ты предлагаешь проверять поля на null тогда?
P>Какие именно поля на null ? ui, dto, bl, конфиг, бд?
Перечитай топик, всё написано. Твоя цитата:
...в составе юнит-тестов, где нас интересуют подробности
— а что если в колонке пусто
P>>>Как без таких тестов сможете убедиться, что на реальной системе у вас действительно эти 30 минут а не месяцы и годы?
P>·>Ты и со своими тестами не сможешь убедиться. Ещё раз, это достигается другим способом. Строишь модель физического времени, например как int64 unix-epoch nanoseconds. А дальше в тестах тупо прибавляешь разное количество наносекунд к моку источника времени и смотришь, что логаут не|произошел. Тогда и конкретное количество времени неважно, хоть 30 минут, хоть 30 лет — тест будет выполяться мгновенно в любом случае. И нет никаких проблем прогонять этот тест каждый раз перед каждым релизом.
P>Смотрите внимательно — щас будут примеры и вы наверняка скажете, что у вас такого быть не может, невозможно, никогда, у вас багов вообще не бывает итд.
Таких примитивных тривиальных багов как у вас — не бывает. Ибо это всё лечится элементарно.
Подавляющее большинство багов — неверно поняли спеку и реализовали поведение не такое, какое хотел юзер. Но такие баги в большинстве ловятся на этапе демо.
P>Итого:
P>Написали вы такой тест на моках, а на проде выяснилось, что юзер всё равно не логаутится. Например, пототому, что в UI приложении есть фоновый процессинг, который мимоходом и обновляет токен продляя сессию.
Так фоновой процессинг не с божьего попущения работает, а с того же мочёного источника времени. Т.е. тест будет выполнять и все шедулеры-фоновые процессы при перемотке времени. В этом и цель этих моков — полный контроль внешних зависимостей. С этим будут проблемы только у тебя, т.к. у тебя по всему коду глобальные переменные в виде DateTime.Now() и никак не контролируются.
P>Пофиксили, и выяснили, юзер всё равно не логаутится, т.е. время жизни сессии берется из конфига, который неправильно смержился.
Не понял. По ошибке указали в прод конфиге не 30 минут, а 300?
На это дело есть специальный процесс, который показывает diff конфига между продом и тестом. Каждая разница должна быть проревьювена и заапрувлена.
P>Пофиксили, и выяснили, что всё равно не логаутится — ваш фикс фонового процессинга сломал один из долгоиграющих кейсов, разработчик Вася подкинул рядом с вашим кодом свой, и фоновый процессинг всё равно обновляет сессию.
Детский сад. Не используйте глобальные переменные.
P>Пофиксили и это, и выяснили, что логаут стартует когда подходит ttl сессии, но ничего не делает — потому что очередь шедулинга с этим связаный забита под завязку другими вещами.
Забитость очереди — это красный сигнал в мониторинге.
P>Пофиксили и это — обнаружили, что строчка тестового кода пролезла на прод в одном из больших пул реквестов и логаут вызывается только для тестовых юзеров.
"строчка тестового кода" это как?! Тестовый код физически лежит в другом каталоге от прода.
P>Проблему нужно решать не моками, а дизайном.
Ага, т.е. опять оффтоп. Мы же тут обсуждаем тесты, а не дизайн.
P>Например — отделить фоновый процессинг от интерактивного, что бы у него даже не было никакой возможности получить токен для обновления.
Мде.

Тупо — не используйте глобальные переменные.
P>А если время сессии это критическая вещь, то e2e ну просится — архитектура аутентификации всегда сложная, там много чего может пойти странными путями.
Это легко лечится: Любая вещь, сложная или не сложная — первый вопрос на который должен быть дан ответ прежде чем приступать к обсуждению дизайна и уж тем более реализации — как мы это можем покрыть быстрыми автотестами?
P>>>Если этот шаг неважный, его в e2e выносить не нужно. А если это важно, то это проверять надо регулярно:
P>·>Ок... ну может логаут неважный. Но вот например "отослать statement в конце каждого месяца" — шаг ооочень важный. Тоже e2e тест сделаешь со sleep(1 month)?
P>В данном случае здесь решение что через мониторинг, что через e2e будет приблизительно одинаковым.
Мониторинг обнаруживает проблемы мгновенно, в отличие от.
P>Разница будет только в том, где именно и как запускается скрипт для проверки что statement действительно создался. e2e можно запускать регулярно, впрочем, я уже это говорил.
e2e чего? e2e — это сценарий, когда какой-то тестовый юзер чего-то сделал и проверяем, что система совершила ожидаемые действия. А statement создаётся для реальных юзеров для действий которые они совершили.
P>>> У вас что, лимит на количество тестов, добавили e2e — теперь надо сотню юнит-тестов удалить? Не пойму ваш кейс.
P>·>Падение e2e-теста означает дыру в нижележащих тестах. Если ваши e2e-тесты падают, чаще чем рак на горе свистит, значит у вас внизу пирамиды дырявые тесты.
P>Нету способа гарантировать отсутствие дыр, багов, уязвимостей итд. e2e это способ задешево выявить большинство проблемав в интеграции верхнего уровня, которая как раз тестами на нижних уровнях не покрывается.
Тут речь идёт о том, что _все_ тесты должны быть запущены и успешно пройдены до того, как код увидят юзеры. А у вас это настолько "задешево", что вы не можете себе этого позволить и выполняеете acceptance частично.
P>·>Я под интеграционным кодом подразумеваю который вызывает "те ошибки, которые проходят мимо ваших моков". Так вот мимо моков проходят ошибки в доле процента кода, который выполняется только при реальном старте приложения, код в том самом composition root.
P>Ну да, вы выдумали какое то своё определение интеграционного кода.
Да мне похрен на определения. Я написал суть. Но на суть тебе плевать, придираешься к терминологии.
P>А ошибки с построением запроса фильтров, они как, по вашему, где ходят?
Не знаю где они у вас ходят. Судя по тому что ты рассказал — на проде.
P>·>У технологического кода другой бизнес-домен. Технологический код, который, скажем, реплицирует базу записей в несколько датацентров — оперирует не бизнес-сущностью лайка, а "запись данных", "датацентр" и т.п. А дальше уже идёт интеграция, когда мы в качестве записи берём лайк и получаем надёжное реплицированное хранилище лайков. У тебя же твой билдер билдит конкретный запрос сущности из бизнес-домена, но вместо ассертов бизнес-сущностей ты тестируешь технические детали.
P>Потому, что покрывать тестами нужно все критические свойства, а не ограничиваться только теми, что в спеке написаны.
Так ты не те свойства покрываешь и не так.
P>·>Только тот код, что в composition root сложно покрывается тестами, т.к. там создаются и инжектятся реальные объекты и требует дорогого e2e тестирования. Остальное — неинтересно, ибо быстро, тривиально и надёжно тестируется с помощью моков.
P>·>Если вы не в сосотянии протестировать контроллер, роутер, юзекйс валидацию и сериализацию без e2e — у вас проблемы.
P>Успокойтесь, e2e это не для теста контролера. Наверное вы забыли, что я вам предлагал тестировать валидацию юнит-тестами?
А чем тестируется контроллер-то?
P>>>Непонятно — вы добавили ровно один тест, и юзеры получили проблему. Такое может быть только в следующих случаях, если
P>·>Ты предложил прогонять не все тесты перед выкаткой в прод.
P>Я вам даже рассказал как именно — все ваши тесты вместе взятые пускаете как сейчас. Допустим их 1000 штук. Вот эту 1000 оставьте и не трогайте.
P>А вот далее вы добавляете новый вид тестов, которые будут запускаться регулярно после деплоя. Их штук 10, новых.
P>Итого — 1000 пускаете как раньше, + 10 новых регулярно.
Зачем, чтобы что? Гораздо выгоднее вместо этой хрени пойти в паб отметить — эффект гораздо лучше.
P>>>Откуда возьмутся проблемы у юзеров на проде?
P>·>Не все тесты выполнены.
P>Похоже, X + 1 у вас может быть меньше X. Забавно!
Потому что твоё "добавление" имеет отрицательный эффект. Тратит ресурсы с нулевой пользой. Зачем это +1 запускать после релиза, если мы можем себе это позволить запустить до? У вас беда в том, что из-за детских проблем в проекте вы не можете эти "10 новых регулярно" запускать ещё за день перед релизом. Я тыкаю пальчиком в проблемы и пытаюсь объяснить что вам надо исправить, чтобы вы тоже смогли, но ты продолжаешь надувать щёки со своей data complexity.
P>>>Ваши имеющиеся тесты отработали — за счет чего регрессия произойдет?
P>·>Наши да, ваши — не все.
P>Непонятно — регрессии откуда взяться? Вы добавили новый вид тестов — старые не трогали. Новые предназначены для регулярного запуска после деплоя.
P>Откуда возьмется регрессия?
Если эти ваши "новые" тесты могут упасть в принципе, то значит у вас регрессия не найденная тестами до деплоя.
Если они не могут упасть принципиально, то зачем их запускать-то?
P>·>Те, для которых написаны тесты — ясен пень не доходят. Если какой-либо тест красный для данной версии системы — в прод она не попадёт.
P>Вот и отлично — значит наличие красных тестов наутро сообщит вам о проблеме еще на стейдже.
Зачем наутро? Через 20 минут же, спасибо мокам.
P>...
P>7 редкие ошибки — прод тупо работает на порядки дольше тестового окружения
Это всё задачи мониторинга и операционного контроля, а не тестов. Тестами в принципе такие задачи надёжно не решаются.
Мониторинг и контроль — другие задачи, другие системы со своим набором тестов, тоже выполняемых до деплоя. Что у вас операционные процессы в плачевном состоянии я ещё больше года назад писал.
P>>>И никто, кроме лично вас не утверждает "на проде багов быть не может"
P>·>Ты меня заебал. Не пиши свои бредовые фантазии как мои цитаты. Я такого никогда нигде не утверждал.
P>Смотрите, вот ваши цитата выше:
P>"Те, для которых написаны тесты — ясен пень не доходят(до прода)" — в скобках это контекст обозначил
И? В логику не умеешь? Помогу: это значит, что могут доходить только те баги, для которых не существует тестов. Из чего ты высосал "багов быть не может" — это мне даже неинтересно.
P>А вы утверждаете, что раз есть тест, то такой баги на проде точно нет 
Ты в логику не умеешь совершенно. Это значит, что этот тест будет зелёным и на проде тоже. Либо он может быть красным синхронно с какой-нибудь лампочкой в системе мониторинга. Что делает запуск теста — бесполезным, никакой новой информации он дать не может.
P>>>Вы из своих функций вызываете другие свои функции? Вот вам и интеграционный код. Посмотрите, сколько у вас такого.
P>·>Непокрытого лёгкими тестами? Полторы строчки, всё верно.
P>Сюда нужно вписать data complexity. Хороший пример — те самые фильтры.
Какое это имеет отношение к интеграционному коду?
P>>>·>Т.е. у тебя есть ровно те же "репозиторий + бд" тесты?
P>>>Есть конечно же. Только таких тестов немного — они дают слабые гарантии в силу своей косвенности.
P>·>Слабые относительно чего?
P>Относительно других методов. Ваши косвенные тесты упираются в теорему Райса.
Ага-ага, а ваши "прямые" тесты не упираются. Да вы круты неимоверно.
P>А вот синтаксические свойства можно обеспечивать той же статической типизацией. Надеюсь, вам теорема Райса здесь не мешает?
P>Кроме синтаксических есть структурные — те самые пред-, пост-, условия, инварианты.
P>Проектирование — формальные методы, например, доказательства тех или иных свойств.
Оффтоп, т.к. мы обсуждаем методы тестирования.
P>·>Возможно. Непонятно почему этот билдер специфичный под этот конкретный метод, а не универсальный типа linq со своими тестами.
P>Как это будет с linq вам Синклер рядом показал. Сама задача в том, что фильтровать нужно по выражению от юзера, который а хрен знает что может понавыбирать.
Я указал на недостатки и дыры в таком подходе в ответе ему.
P>>>Все функциональные требования удовлетворены. Непонятно, почему тесты должны падать.
P>·>Потому что попытка юзера выполнить функцию проваливается из-за ошибок в синхронизации.
P>Необязательно, перестаньте фантазировать.
Ну так и моки падают необязательно, перестаньте фантазировать.
P>·>Ещё раз, эта проблема ассертами в тестах не решается.
P>В том то и дело. А что у вас есть кроме тестов?
Всё что надо, не волнуйся, но это оффтоп. Если интересно, заводи новую тему.
P>·>Верно. Но ты не догоняешь, что во 2м пункте можно просто ассертить число записей, с тем же успехом, но лучшим результатом.
P>Что бы ассертить число записей нужно знать комбинацию которой у вас точно нет.
Нужно знать ровно то же, что и у вас.
P>>>Вы из 1..4 видите только тесты, а всё остальное для вас пустое место.
P>·>Не потому что пустое место, а потому что мы тут обсуждаем тесты и разные подходы к тестированию, а 1..3 — оффтопик. Но ты всё не успокоишься и продолжаешь словоблудить.
P>Никакой это не оффтопик. пп 1 2 и 3 говорят о том, что можно изменить дизайн, и ваши моки будут больше не нужны.
Может быть, но тебе не удалось. Ни для примере Буравчика, ни в примере Фаулера.
P>>>Каким образом .top(10) пропустит десятки миллионов записей? подробнее.
P>·>Поставлен не туда или поставлен условно.
P>Вот вам и стало понятно, что покрываем тестами — поставлен именно туда, куда надо. Только сначала дизайн решения. См сообщение Синклера
Похрен на дизайн. Ты простую мысль так и не понял. Проверять кол-во записей и проверять наличие top — даёт те же гарантии. Но проверка кол-ва записей проверяет больше.
P>·>_такой_ тест не нужен. Нужен другой тест.
P>Другой, которого вы так и не показали?
Показал.
P>·>Т.е. твои тесты — проверяют меньше, чем мои. Мои, помимо того, что кол-во записей ограничивается 10ю так же протестирует и валидность запросов, подстановку парамов и т.п.
P>Мои тесты фиксируют структуру решения. Ваши без конкретного перечня комбинаций ничего не гарантируют.
Гарантируют то же что и твои.
P>>>Облегчают. Вместо погружения во все детали реализации во время код-ревью, вы смотрите какие тесты были исключены.
P>·>Ты о чём? Что за исключённые тесты?
P>Закоментили, удалили, исправили ожидания. Если вы видите, что тест на .top убрали, надо пойти и дать по шее.
Детский сад какой-то.
P>>>acceptance в минутах считается только для hello world.
P>·>Завидуешь, да? Ну вообще говоря acceptance гоняется на кластере, вот и укладывается в пол часа.
P>Полчаса это десятки минут. e2e это вобщем тот же acceptance. Если у вас есть такое, чего же вы здесь выступаете?
Выступаю о том, что это всё выполняется ещё до деплоя. Не нужно выполнять ничего после деплоя (ок, один smoke test), и уж тем более частично по random.
P>·>В тесте же конкретный сценарий — запускаем код, дождались завершения, проверяем, выполнилась ли инструкция X. Никакой проблемы останова.
P>Вы успешно опровергли теорему Райса
P>>>Вот-вот. Вы путаете синтаксис и семантику. Любой компилятор справляется и с синтаксисом, и со структурой, но не с семантикой.
P>·>Так ты зачем-то синтаксис и проверяешь "есть ли в коде .top(10)".
P>В том то и дело — я проверяю структуру, а вы пытаетесь тестами семантику проверять. Отсюда ясно, что вашими тестами вы в теорему Райса упретесь гораздо раньше
Ты не проверяешь структуру, ты копипастишь её из прод-кода в тест-код. Т.е. для надёжности для надёжности пишешь пишешь дважды ровно то же самое то же самое. А то вдруг чего. А то вдруг чего.
P>·>Если я правильно понял проблему, то она не находится никакими тестами, хоть ручными, хоть ножными. Если только случайно.
P>Её можно исключить методами родственными знакомой вам статической типизации. Те самые предусловия и соответствующий дизайн.
Похрен. Идёт речь про тесты. Ты заявляешь "Вы так и не показали ни одного автоматического теста". И что, и не обязан был. Ты не показал вообще никакого теста. И не сможешь, ясен пень.
P>>>Там, где у автоматических тестов начинаются недостатки, у других методов будут преимущества.
P>·>Если ты под другими методами имеешь в виду ручные тесты, то у меня для тебя плохие новости.
P>Ручные методы это в т.ч. exploratory, и вообще исследование.
И? Из ручного тут лишь само создание автоматических тестов. Да, если ты не знал — код тестов пишут вручную. Если вы их герените автоматом, то не делайте так больше.
P>·>Главное пока умалчиваешь: тест как выглядит для этого кода? Ну где там deep.eq, pattern или что?
P>Вам примера Синклера недостаточно, вы хотите у меня тож самое спросить?
P>P>const request = create(
P> User,
P> u => u.many(q => q.filter(f => f(filterExpression))
P> .orderBy(o => u('created'))
P> .top(10)
P> )
P>);
P>expect(builder({ параметры })).to.deep.eq(request)
P>
P>вот так мы можем проверить, добавляет ли билдер top или нет. Билдер будет примерно как у Синклера.
Не понял. Где тут прод-код, где тут тест-код? Напиши однозначно — код под тестом и сам тест.
P>>>Ищите по огромным синим буквам.
P>·>Там нет ответа на этот вопрос. Там сказано "далее ...бд минимально заполненой", а что было с бд до "далее" — ты надёжно скрываешь.
P>Забавно, вы вырезали часть цитаты, и не знаете, что было в той части, что вы же и выбросили? Ищите — я для вас синим подсветил
Нашел. Там нет ответа на мой вопрос.
P>·>Какие поля когда могут быть null — это дохрена комбинаций в типичном приложении. Т.е. получается, что ты интеграцию null-полей проверяешь только на юзерах.
P>Пример у вас есть?
Всё тот же, не теряй контекст.
P>>>Вам нужно знание о том, как устроены четные и нечетные — у одних младший бит 1, у других — младший бит 0
P>·>Отлично. Вот ты и выявил какие комбинации будут проблемными. Придумать входные парамы и ожидания с вариациями младшего бита. Т.е. и тестировать надо именно на комбинациях младшего бита.
P>Комбинации как раз не выявлены. Только свойство построения чисел
Вариации младшего бита и есть проблемные комбинации.
P>>>В переводе на фильтры — у запроса всегда есть лимит.
P>·>"у запроса всегда есть лимит" в переводе в твоём случае будет "функция isOdd всегда использует битовую операцию взятия младшего бита".
P>Вы уже почти научились. В случае с битами все просто — половина целых четные, половина — нечетные. Это значит, что тестовый набор вы сможете намастырить самостоятельно.
Половина бесконечности, если что — тоже бесконечность.
P>А вот где взять запрос, у которого будет нарушено свойство длины — загадка
Что за свойство длины?