Здравствуйте, ·, Вы писали:
P>>·>Недостаточно для чего? Почему недостаточно? Причём тут таблица истинности?
P>>Логику, вычисления мы тестируем по таблице истинности. И чем меньше дополнительного кода сверх этой таблицы истинности, тем лучше. А вам надо все поразмазывать по мокам
·>Ну тестируй. Моки тебе ничем не мешают.
Мешают — хрупкие тесты, т.к. вайтбоксы, и дополнительный приседания что бы обмокать зависимости
P>>Функционально — ровно столько же.
·>Нет. Он у меня ещё и содержит склейку. У тебя склейки нет.
Нету такой функции как склейка. Вы все еще думаете вайтбоксом.
P>>·>Меньше интеграционных за счёт того, что они тестируют интеграцию. А не всю копипасту, которую ты предлагаешь плодить.
P>>Моки не тестируют интеграцию. Моком вы можете проверить, а что будет, если подкинуть ту или иную зависимость. А нам надо совсем другое — готовый компонент работает как нам надо.
·>Ты читать умеешь? Ты где увидел в моём предложении выше слово "моки"? Хинт: моки вообще ничего не тестируют. Тесты — тестируют.
Тесты на моках интеграцию не тестируют, и не могут. Тест интеграции — проверка функционирования в сборе, а не с отрезаными зависимостями.
P>>Количество интеграционных тестов моки уменьшить никак не могут. Моки — это фактически понижение уровня тестирования за счет обрезания зависимостей. Нам же надо не понижение, а повышение.
·>Могут, т.к. большинство логики тестируется ю-тестами. А и-тесты нужны только чтобы тестировать интеграцию уже протестированных компонент.
Вот у вас снова из за моков почему то интеграционных тестов становится меньше. Вы путаете два противоположных случая — тест со включенными зависимостями и с обрезанными.
P>>·>Как немного? Ты пишешь по интеграционному тесту для каждого do_logic. Т.к. именно там происходит склейка.
P>>Есть метод — его нужно вызвать в тестах. И у вас будет ровно то же. Просто вас тянет тестировать код, а не ожидания вызывающей стороны.
·>У меня такого метода просто не будет. Следовательно и тестов писать просто не для чего.
Куда ни ткни у вас "таких проблем у меня не может быть".
P>>Вместо проверки конкретной склейки делаем интеграционный код линейным, буквально, а интеграцию осуществляем на самом верху.
·>Чем выше, тем больше мест. Функция nextFriday() осуществляет склейку у себя внутри. И покрывается одним тестом. У тебя будет nextFriday(now) — и на самом верху будет множество call site для этого накопипастено. Код линейный, да, но накопипастен в кучу мест.
Нужно проверять все эти call site вне зависимости от способа доставки депенденсов, каждая функция должна быть вызвана в тестах минимум один раз.
P>>Простите, вы мапперы из одной структуры в другую как тестировать собираетесь?
·>В ю-тестах — по частям. Иначе изменение логики маппинга одного поля сломает все deep.equal тесты, где это поле есть.
Вы наверное не в курсе, то в джаве типизация хилая — не позволяет внятно типизировать согласованые значения, например "если ид = 0" то "created = null"
А раз так, то вы будете выписать такие согласованые значения руками.
Следовательно, и тестировать нужно ровно так же, а не размазывать значение по разным тестам
Будь у вас фукнциональный язык, можно было бы типизировать чуть не все подряд, но у вас такого фокуса нет.
P>>Пусть используется. Что вас смущает ?
·>Что в каждое из этих мест тебе понадобится копипастить склейку nextFriday(now) с источником текущего времени и покрывать это ещё одним тестом. Хотя, как я понял, ты вообще заявил, что такое протестировать ты просто не сможешь.
Вы кроме как вайтбоксом думать не хотите. "тестировть склейку" — это тупой вайтбокс, со всеми его недостатками. Вайтбокс в мейнтенансе дороже блакбокса. Вам это каждая ссылка в гугле скажет.
Не надо тестировать склейку — нужно тестировать результат той или иной функции. И тут по барабану, что откуда вызываете — есть функция, её нужно связать с таблицей истинности и покрыть тестом.
Вы же все время намекаете, что ваши моки от этого избавляют.
·>Ещё раз. nextFriday() ≡ nextFriday(now) ∘ timeSource.now(). Если ты отказываешься использовать в call site готовый и протестированный nextFriday(), значит тебе в каждый call site придётся протаскивать timeSource и копипастить композицию с nextFriday(now). Это увеличивает кол-во прод-кода и требует больше более тяжеловесных тестов для покрытия всей копипасты.
Вам точно так же нужно протаскивать timeSource, только без параметра. И тестировать нужно ровно столько же, т.к. нужно знать, как ведет себя вся интеграция разом.
P>>Читайте себя "Так функция может использоваться из множества мест."
·>И?
Вы же все эти места обмокали. Вот новый девелопер пришел на проект, откуда ему знать, должно его изменение повлечь правки моков или нет?
P>>У вас в тех самых тестах все будет обмокано. Как узнаете, что там, в моках, должно вызываться не "то", а "это"?
·>Эээ.. Ты рефакторингом точно умеешь пользоваться? Компилятор и IDE всё покажет, подскажет и подправит.
Вы здесь жульничаете — по факту вы мне задали тот же вопрос, что и я вам. Но у меня, по вашему, будут проблемы и ни компилер, ни иде не помогут, а вот вам в аналогичной ситуации будут помогать
Я же вижу, что с чистыми функциями помощи от компилятора кратно выше
В некоторых случаях кода писать больше, за счет того, что в других — намного меньше, и бОльшую часть можно переложить на компилятор и иде.
Например, нужно заинлайнить функцию
с чистой функцией это нажал на кнопку и получил результат
с вашими зависимостями компилер говорит "приплыли" потому что в текущий блок зависимость не подложена, и компилер не в курсе, как правильно её привязать.
Ровно так же дела с переносом кода куда угодно, выделение наследника, сплющивание иерархии, конверсии класса в функцию и обратно
А вам всегда будет мешать та самая зависимость
Если вы не согласны — покажите как ваша иде инлайнит код nextFriday по месту каждого из call site. Явите же чудо, про которое вещаете тут годами
P>>·>Ты потерял контекст. Тут шла речь о ю-тест упоминал "а что если в колонке пусто". В колонке, внезапно окажется, будет не пусто а дефолтное значение из бд. Багу такую поймаешь только на проде, т.к. и-тесты для таких подробных мелочей явно писать не будешь.
P>>Наоборот — именно для таких мелочей юнит-тесты и нужны.
·>Ты не читаешь, что тебе пишут.
Наоборот. Я как раз для подробных мелочей и пишу юниты-тесты. Вероятно, вы делаете иначе.
P>>Что там будет с бд, когда другой девелопер чего нибудь фиксанет — а хрен его знает.
P>>А если таблица истинности рядом с тестами и тестируемой функцией, шансов намного больше что проблему заметят еще во время код ревью.
·>Нет, не пытаюсь, ты опять фантазируешь. Я пытаюсь донести мысль, что надо проверять что код делает, а не как он выглядит.
Еще раз — у меня нет буквально в коде того или иного запроса целиком, а есть конструирование его. Я ж прямо пишу — построение запроса по фильтрам.
Это значит, что у нас
1. связывание
2. маппер туда
3. маппер обратно
+ шаблоны запроса, шаблоны фильтров итд
То есть, у нас в наличии обычные вычисления вида object -> sql которые идеально покрываются юнит-тестами
P>>Интеграционный тест проверяет всю интеграцию разом, а вас тянет проверить каждую строчку. Каждая строчка — это про юнит-тестирование.
·>Твой один интеграционный тест проверяет интеграцию одного do_logic. Таких do_logic у тебя будет дофига, и каждого надо будет проверить.
Этот do_logic по одному на юз кейс. Сколько юз кейсов — столько и таких методов, а значит столько будет и интеграционных тестов. И у вас будет ровно то же. И никаие моки этого не отменят.
Даже если вы вообще удалите зависимость от Time.now, это ничего не изменит — количество интеграционных тестов останется прежним
P>>Какой такой? Вам всё равно нужен интеграционный тест. Задачи интеграционных тестов не каждую склейку проверять по отдельности, а проверять работает ли компонент собраный целиком. Что там унутре — для интеграционного тестирования по барабану — нужная функция работает, значит всё хорошо.
·>Интеграционный тест чего?
Чего угодно — хоть системы, хоть приложения, хоть компонента.
P>>·>Именно. Т.е. усложняешь прод-код, теряешь возможность протестировать и ловишь баги в проде. Нам такого не надо.
P>>Забавная телепатия.
·>Никакая не телепатия. Если ты никак не можешь протестировать, то проблемы будут обнаруживаться в проде. Ок, возможно, ещё при ручном тестировании.
Я и говорю — телепатия. Вы лучше меня знаете, что у меня в коде, что у меня за проект, где больше всего проблем возникает, сколько должен длиться билд
P>>>>У вас причин для изменения гораздо больше — любое измение дизайна означает поломку ваших тестов на моках.
P>>·>Это страшилки.
P>>Это следует из ваших примеров.
·>Не следует.
Именно что следует. Вы топите за вайтбокс тесты, а у них известное свойство — поломки при изменении внутреннего дизайна.
У вас выходят вайтбокс тесты без недостатков свойственных вайтбокс тестам.
Чудо, которое можно объяснить только вашими фантазиями
P>>Обычное правило — 1 инструкция на строку. Вы втюхали минимум две.
·>И что? Небо на землю упадёт?
Выглядит так, что вы отрицаете недостатки моков и вайтбокс тестов, даже посредтством такой вот дешовой детской подтасовки.
P>>А поскольку у вас значения захардкожены, то между разными тестами согласованность никак не проверяется, т.к. везде хардкодите значения.
·>Ну ввести константу — не проблема.
Её нужно вводить, хотя бы для того, что бы обеспечить согласованность некоторых тестов.
А все лишние из тестов нужно убрать, что бы ничего не мешало делать ревью
Чем больше, тем лучше. Если моки можно убрать — их нужно убрать
P>>·>Именно. Так что неясно зачем ты делаешь эти предъявы о гарантиях. У тебя аргументация вида "Раз ваш подход не умеет кофе варить и тапочки приносить — значит это плохо и надо делать как фаулер завещал".
P>>Вы забыли, что именно вы претендуете что решите это всё тестами.
·>Опять фантазии. Давай в следующий раз когда ты решишь что я думаю, на что я претендую, и т.п., подкрепляй моими цитатами.
Вы же пишете, что вам на проверку любой сложности фильтров хватит одной тестовой бд с ничтожным количетсвом записей.
P>>Его можно ограничить контролируя построение запроса + таблицу истинности храним не абы где, а рядом. Вы же все хотите таблицу истинности или размазать, или запихать куда подальше.
·>Не знаю где ты собрался размазывать и запихивать таблицы, просто не делай так, я разрешаю. Но это не отвечает на вопрос, куда делся человеческий фактор-то?
Если вы таблицу истинности размазали по бд, вам нужны административные меры, что бы заставить девелоперов собирать всё в кучку на код-ревью или для разработки.
Нет такогого — значит часть изменений будут идти на авось
А если таблица истинности рядом — проверить её обычно секундное дело. Можно даже тестировщиков привлечь, и бизнес-аналитиков — кого угодно, в отличие от вашей схемы с бд
P>>Интеграционные тесты не проверяют варианты склейки — они проверяют функционирование в сборе. Юнит-тесты проверяют работоспособность примитивов.
·>У тебя плодится много точек сборки, которые теперь приходится проверять.
Проверять нужно не точки сборки, а всю сборку целиком. Точки сборки — та самая вайтбоксовость с её недостатками, которые вы отрицаете уже минимум несколько лет
> Ты решил терминов наизобретать? Что такое "работоспособность"? Чем она отличается от функционирования?
Функционирование и работоспособность это слова-синонимы. В руссокм языке это уже давно изобретено.
P>>Не из кода, а из требований вызывающей стороны.
·>Что за требования вызывающей стороны, которые диктуют, что должен быть написан код с fn2, а не fn3? Вызывающая сторона это вообще что и где?
Например, те самые требования. Если нам вернуть нужно User, то очевидно, что fn2 должна возвращать User, а не абы что.
Вызывающая сторона — в русском языке это значит та сторона, которая делает конкретный вызов.
P>>Это ваша фантазия — эдак у вас юнит-тесты станут code smell, тк они принципиально по своей сути видят слишком много.
·>У нас юнит-тесты видят те же публичные методы, что и используются из других мест прод-кода. Тестировать то, что видно только тестам — это и есть твоё "как написано", завязка тестов на детали внутренней реализации.
Вы снова додумываете вместо того, что бы задать простой вопрос.
·>Я не знаю что такое содержимое тестовой бд и накой оно вообще нужно.
Во первых, врете, см ниже
Ну как же — вы собирались фильтры тестировать посредством выполнения запросов на бд, те самые "репозитории" которые вы тестируете косвенно, через БД. Или у вас фильтрация вне репозитория сделана? Ну-ну.
P>>Вероятно, это особенность вашего проекта. Любая более-менее внятная статистика-аналитика по бд это довольно сложные алгоритмы, и здесь нужно чтото лучше, чем смотреть в бд и думать, что же должно быть на выходе.
·>Верно. Я уже показал что лучше — сохранить данные в бд и поискать их разными фильтрами.
А вот и доказательство, что врете — здесь вы знаете что такое содержимое бд и накой оно нужно.
P>>Раскройте глаза — здесь блекбокс. Выборочно вызываем бд нашим кодом, проверяется весь пайплайн в сборе, косвенно. Только нам не надо проверять всё на свете таким образом, т.к. есть и другие инструменты.
·>"я знаю, как строятся фильтры" — это и есть whitebox, не лукавь.
Как строятся — какой должен получиться в итоге запрос. А вот подробности того, какого цвета унутре неонки(связывание, конверсия, маппинг, итд) — мне не надо.
Чем сложнее логика построения запросов — тем больше тестов придется писать. Косвенные проверки не смогут побороть data complexity
P>>Вы никак не можете объяснить преимущества размазывания таблицы истинности по тестами и бд, чем это лучше хранения таблицы истинности рядом с кодом и функцией с тестом.
·>Размазывание таблицы истинности придумал ты сам, сам и спорь со своими фантазиями.
Ну как же, смотрите выше — "лучше — сохранить данные в бд и поискать их разными фильтрами."
P>>Затем, что доказательство корректности — это необходимое условие. А такое доказательство + тесты + код ревью, необходимое и достаточное.
·>Если у тебя есть доказательство корректности кода, то тесты уже не нужны. Это и есть идея доказательного программирования.
Ну и дичь
Каким чудом ваше доказательство сработает, если в код влезет другой ?
Дональд Кнут на линии: "Остерегайтесь ошибок коде; я только доказал его правильность, но не проверял его."
P>>·>Это значит, что изменение в коде занимает как минимум день для выкатки в прод. Значит глобально архитектура выбрана плохо. Возможно надо резать на независимые компоненты.
P>>Нет, не значит.
·>Ты сказал, что процесс билда и тестов занимает 2.5 часа. Это уже пол дня.
P>>Вы не в курсе, ни что за проект, ни какие требования, итд. Далеко не все проекты могут протаскивать изменения в прод прям сразу.
·>Я знаю, но это обычно недостаток, а не повод для гордости.
А еще чаще это признак огромного проекта
P>>Я ж сказал — если по аннотации можно сгенерировать 4 артефакта, то почему нельзя сгенерировать 5й, 6й, 7й?
P>>Вы же видите только переписывание
·>Вопрос в том, что является источником — прога на конкретном яп или language agnostic описание контракта.
language agnostic описания, если вы про json, это отстой, т.к. удлинняет цикл разработки — есть шанс написать такой манифест, который хрен знает как заимплементить
Такое описание далеко не всегда нужно:
1. например, у нас всё на джаве — джава, скала, котлин, итд.
2. например, у нас нет внешних консумеров
3. например, мы связываем части своего собственного проекта — здесь вообще может быть один и тот же яп
P>>·>Но при сохранении контракта, который у вас описан на аннотациях конкретного ЯП. В общем гугли ликбез, например, тут https://swagger.io/blog/code-first-vs-design-first-api/
P>>Вы путаете code-first и design-first. design first — означает, что первое деливери это апи, а не реализация. code-first — наоборот. А какой файл вы в начале редактируете, json или java и yaml, дело десяток
·>Не десятое, а первое. Погляди в словаре что означает слово "first".
design-first означает, что в первую очередь деливерится апи, а не абы что. А вот как вы его сформулируете — json, idl, grapql, grpc, интерфейсы на псевдокоде, java классы без реализации — вообще дело десятое, хоть plantuml или curl.
Здесь самое главное, что бы мы могли отдать описание всем, кто будет с ним взаимодействовать. А уже потом начнем работать над реализацией.
P>>Я ж сразу сказал — апи уже есть, а реализации нету, зато можно и тесты писать, и клиентский код, и документацию прикручивать
·>А начался разговор, что у тебя аннотации хитрые и сложные, зависят от переменных окружения и погоды на марсе.
Основа апи остаётся. Переменные окружения и конфиги не могут поменять параметры метода, типы, результат итд. Но могут скрыть этот метод, или добавить метаданные, например, метод начнет требовать авторизацию, или наоборот, будет работать без авторизации.