Re[37]: Что такое Dependency Rejection
От: Pauel Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.01.24 16:03
Оценка: +1
Здравствуйте, ·, Вы писали:

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>>Я ж сразу сказал — апи уже есть, а реализации нету, зато можно и тесты писать, и клиентский код, и документацию прикручивать

·>А начался разговор, что у тебя аннотации хитрые и сложные, зависят от переменных окружения и погоды на марсе.

Основа апи остаётся. Переменные окружения и конфиги не могут поменять параметры метода, типы, результат итд. Но могут скрыть этот метод, или добавить метаданные, например, метод начнет требовать авторизацию, или наоборот, будет работать без авторизации.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.