Здравствуйте, Pauel, Вы писали:
P>>>Моки изначально предназначались для тестов вида "вызываем вон то, вон так, в такой последовательности"
P>·>Может быть. Неясно какое это имеет значение сейчас, так исторические курьёзны. Даже если посмотреть на историю библиотек для тестов — за много лет много чего менялось и переделывалось.
P>И сейчас это основной кейс для моков.
Я не знаю где это основной кейс. Можешь посмотреть туториалы по тому же mockito, там такого треша нет.
P>Вы и сами тащите "надо проверить old и new", и другого варианта не видите, как будто его нет. Можно же и дизайн поменять, что бы юнитами такое проверять. Но нет — вы топите за моки.
Есть, конечно, но другие варианты хуже. Больше писать кода и сложнее тестировать.
P>>>У вас — охотно верю.
P>·>Потому что у нас не хелловорды, а не как у вас, да?
P>Потому, что вы используете дизайн, который плодит лишнее. Я вам на примере дата-время показал, как можно иначе, но вам любой пример не в вашу пользу надо забраковать.
По факту пока что кода лишнего больше у тебя. Притом "вот фаулер написал моки — плохо, давайте накрутим слоёв в прод коде!".
P>>>Я вам пример приводил, про время, вам он ожидаемо не понравился — язык не тот
P>·>Я не понял к чему ты скачешь с одного на другое. Обсуждали статью и MaitreD, потом crypto api, теперь вот ещё time api зачем-то...
P>Со статьё давно всё ясно. crypto api и time это пример, которые показывают, за счет можно отказаться от моков, и что будет, если этого не делать.
Ни для crypto api, ни для time моки не нужны обычно не потому что "дизайн", а потому что они быстрые, детерминированные, с нулём внешних зависимостей.
P>>>В данном случае мне не надо переживать за поломаные тесты, если понадобится другой алгоритм, другая либа, итд.
P>>>Вот понадобился не hmac а что другое — в файлике samples поменял десяток значений, и всё
P>·>Почему десяток? У тебя только десяток операций в api?
P>Это у вас на моках упадут все тесты всех операций апи. О том и речь. А на обычных юнит-тестах вы подкидываете новый набор значений, и всё путём.
Почему десяток? У тебя только десяток операций в api? Откуда взялся десяток?
P>>>А ваша альтернатива этому — еще и тесты перебулшитить.
P>·>Один, скорее всего. Ибо одного теста достаточно чтобы зафиксировать логику вычисления hmac. В остальных тестах достаточно ассертить его наличие, но не конкретный формат.
P>"достаточно ассертить его наличие" — вот вам и привязка к "как написано"
Не понял. Наличие hmac — это ожидание, бизнес-требование.
P>Ага, тесты "как написано"
Вам придется написать много больше, чем один тест — как минимум, пространство входов более-менее покрыть. Моками вы вспотеете это покрывать.
Я тебе показывал как надо моками покрывать.
P>>>Ну да, этож только у вас сложные системы.
P>·>Ну да, сам же сказал, что у тебя всё помещается в один файлик. Или он гиговый?
P>Вы там в телепатию заигрались? Что именно по вашему помещается в один файлик? Вся система, все тесты, вся система с тестами?
P>Вы чего то недопоняли, но вместо уточнения начинаете валять дурака?
А толку уточнять. Я задал вопрос чего десяток — ответа так и не последовало.
P>·>Какой негатив? Вроде говорили об одном, теперь чего-то новое.
P>·>Вообще неясно причём тут time api и причём тут моки и тестирование вообще.
P>time api это пример дизайна, как можно уйти от комбинаторного взрыва.
Это не "дизайн". Это если ЯП умеет в duck typing и сооружать типы на ходу. Впрочем, тут явно фича применена не по месту.
P>>>Успокойтесь — это все статически контролируется, только в вашу джаву такие фичи еще не завезли.
P>·>Спасибо, но сводить всё к массиву из 7 чиселок — это фигня полная и издевательство. Даже такое DateTimeOffset.from({...time.toFields, ...date.toFields(), offset: serverOffset}); — и всё поехало. И где наносекуды, интересно?
P>Где вы видите массив? Это объект, статически типизированый, наносекунды будут в time.toFields как fractionalSeconds. Вам телепатия еще не надоела?
Ужас. Закопайте.
P>·>Конструкторы удобнее и надёжнее с нужными типами, например, OffsetDateTime.of(date, time, offset), это хотя бы читабельно, и если что-то не так, не компиляется
P>Принципиальное отличе of вместо from
Принципиальное отличие что тут три разных типа Date, Time и Offset — и их никак не перепутать.
P>>>Вы уже показали — перебулшитить все тесты, когда можно ограничиться десятком строчек на весь проект.
P>·>Это твои фантазии.
P>Вы сами пишите, что тестировать надо "как написано", это следует из того, как вы предлагаете решать задачу с hmac. Таких же задач будет не одна на проект, а целая куча. Вот и будут тесты "проверить что делает"
Я предложил как решают задачу взаимодействия с неким абстрактным сложным API в тестах с моками (стабами?). То что это crypto — к сути дела не относится, я это сразу заявил в ответе на твой пример, перечитай. Так что это твои фантазии.
P>>>Ну да — для вас перебулшитить тесты проблемой не является
Еще и настаиваете, что так и надо.
P>·>Я настаиваю, что так не надо.
P>Если не надо, то должен быть другой подход к тестированию. А вы выбираете тесты на моках "проверим что вызывается hmac с нужными параметрами"
У меня в примере не было "проверим что вызывается hmac с нужными параметрами". Это было у тебя, и я сказал, что так не надо.
P>>>Проходит же. Вот я и интересуюсь, кто настрочил горы непотребства
P>·>Вчерашние студенты?
P>Да не похоже.
Ок, пусть сорокалетние+ джуниоры.
P>>>Эта разновидность тестов нужна и вам.
P>·>Нужны, но не для проверки каждой строчки кода, что параметры вызова не перепутаны. А только для тестирования интеграции.
P>АПИ и есть та самая интеграция.
Нет.
P>>>Продукт, система, приложение, апи, компонент, модуль. Для теста именно кода у нас другие инструменты — код-ревью, линт, дизайн-ревью, статические анализаторы, итд.
P>·>Я сказал "Они отменяют необходимость написания тучи этих самых xxxComposition, нет кода — нечего тестировать". Ты прикопаться решил к слову код? Ок, пусть будет не код, а модуль-компонент.
P>·>"Моки отменяют необходимость написания тучи этих самых xxxComposition, нет такого компонента|модуля — нечего тестировать." Так яснее?
P>Не отменяют. Когда вы укрупняете компонент, то тестировать его сложнее. Или ваше покрытие будет решетом, или вам придется понаписывать много моков вида "это вызывает то", которые сломаются даже при минорных изменения компоненты
Суть в том, что компонент содержит несколько частей функциональности и весь компонент покрывается со всей его функциональностью, с моками (стабами?) зависимостей. После этого достаточно одного интеграционного теста, что несколько компонент соединились вместе и взаимодействуют хотя бы по одной части функциональности. Условно говоря, если в классе 20 методов и все 20 протестированы сотней юнит-тестов, то для тестирования интеграции обычно достаточно одного и-теста. В качестве аналогии — когда ты вставляешь CPU в материнку — тебе достаточно по сути smoke test, а не прогонять те миллионы тестов, которые были сделаны на фабрике для каждого кристалла и конденсатора.
У тебя же будет дополнительных xxxComposition на каждый метод в прод-коде и это надо будет всё как-то тестииовать в полном сборе.
P>>>Можно. И это делается без моков. Если мы заложимся на значение или состояние, то получим куда больше гарантий.
P>·>Без моков ты предложил только полный запуск всей аппликухи, в лучшем случае с тестовой субд. Kafka/amps/lbm/solace/tibco/etc, кстати, тоже тестовую будешь пускать? Или как?
P>Вы додумываете. Это в вашем понадобился бы запуск всей апликухи. У меня же апликуха запускается только ради e2e тестов.
P>Кафка — это обычный эвент, как вариант, можно обойтись и простым юнитом, убедиться что функция возвращает объект-эвент.
P>Если у вас такой роскоши нет — добавьте мок ровно на нотификацию, а не на кафку.
Так вызов метода — это и есть по сути эвент. По крайней мере, изоморфное понятие.
P>>>В функции средний девелопер может понаделывать ошибок куда больше, чем перепутать old и new.
P>·>Я в этом и до среднего не дотягиваю, дохрена таких ошибок делаю, но вся эта фигня на раз ловится тестами, c моками (стабами), да.
P>Если вы написали тест на old и new, то конечно же словится. Только откуда следует, что это единственные проблемы?
P>Проблем может быть сколько угодно, именно конечный результат говорит что правильно а что нет
Не знаю как у тебя, но у меня большинство ошибок именно логике в реалзиации методов, когда я тупо ошибаюсь в +1 вместо -1, from/to и т.п.
P>>>Именно! А потому нам все контроллеры нужно тестировать в апи тестах — тем самым мы исключаем добрый десяток классов проблем.
P>·>И эти тесты дадут тебе гарантию?
P>Разумеется, мы ради этого и пишем тесты. Не только что бы убедиться, что работает здесь и сейчас, но что бы можно было перепроверить это в т.ч. на живом окружении.
P>После билда работает, после деплоя — нет, опаньки!
У меня такое редко бывает. Неделю мучаюсь, вылизываю corner cases, потом деплою и оно тупо работает. Ну или сразу грохается при запуске, т.к. новый парам забыл в конфиге определить и лечится за минуту.
P>Впрочем, в прошлом году вы рассказывали, что деплой трогать низя — он у вас хрупкий, не дай бог повалится от лишнего запроса.
Это ты фантазируешь. Не "повалится", а произойдёт реальная сделка.
P>·>Жуть. Ну ладно. Т.е. тут мы тестируем репозиторий и ассертим текст sql
P>Здесь мы тестируем построение запроса
Ассерт-то в чём? Что текст запроса 'select * from users where id=?'? У тебя в тесте именно текст забит или что?
P>·>Как проверить, что текст запроса хотя бы синтаксически корректен?
P>Для этого нам всё равно придется выполнить его на реальной бд. Расскажите, как вы решите задачу вашими моками.
Я уже рассказывал. Интеграционным тестом repo+db. Текстов запроса в тестах нет, и быть не должно. Как-то так:
var testSubject = new MyRepo("connectionString");// по возможности in-mem dbms, но может быть и реальная
var id = 42;
testSubject.save(new User(id, "Vasya")));
var actual = testSubject.getUser(id);
assert actual.getName().equals("Vasya");
>> И что он при выполнении выдаст то, что ожидается?
P>А здесь как вы моками обойдетесь?
Тут и не надо. Здесь же интеграция с субд тестируется. Моки (стабы?) будут дальше — в бл, в контроллере, етс.
>> И как ты собрался тут подменять субд? Ты обещал, что теперь эту хрень можно отдать любой db и оно выдаст одинаковый результат? Даже если эта субд это oracle или cassandra? Да там синтаксис банально другой.
P>А разве я говорил, что бд можно менять любую на любую? Построение запросов мы можем тестировать для тех бд, которые поддерживаются нами.
У тебя был такой код:
const getUser = repository.getUser(id);
const oldUser = db.execute(getUser);
Этот код
выглядит так, что getUser выдаваемый из репы не зависит от db (и как ты заявил обещано в clean) и repo покрывается тестами независимо. Но по сути всё то же самое. Просто зависимость стала неявной. "генерим любой результат, но только такой, который где-то как-то будет использоваться в db.execute и мы должны знать где и как". Иными словами, repo может генерить только такие результаты, которые можно использовать далее, пишем репу, но должны всё знать о db слое. И вот это никак не тестируется без запуска всего кода контроллера в котором живёт этот код. А чтобы запустить контроллер — надо обеспечить ему все зависимости, т.е. по сути запустить всё приложение.
В моём коде выше с
MyRepo("connectionString") — мы тестируем только интеграцию двух частей repo + dbms. И ничего больше в таких тестах поднимать не надо.
P>>>Сами трансформации тестируются отдельно, обычными юнитами, например expect(fn1(user)).to.eq(user.id);
P>·>Так ведь надо трансформировать не некий user, а конкретно ResultSet возвращённый из "select *". Что колоночки в select местами не перепутаны, как минимум.
P>Что вас смущает? трансформация результата принимает ResultSet и возвращает вам нужный объект.
Так ведь надо не абы какой ResultSet, а именно тот, который реально возвращается из "select *". У тебя же эти по настоящему связанные сущности тестируются независимо. Что абсолютно бесполезно.
P>·>Ещё это всё "красиво" только на твоих хоумпейдж проектах. В реальном коде эти sql будут сотни строк с многоэтажными джойнами и подзапросами, и такие "тесты" станут даже немножечко вредить.
P>Расскажите, как вы это моками решите
Моки (стабы) — это для отпиливания зависимостей в тестах. Репу тестируем медленными и-тестами с более-менее реальной субд, а дальше моки (стабы) для быстрого тестирования всего остального.
P>>>Вы все думаете в единицах старого дизайна, когда БЛ прибита гвоздями к бд.
P>·>Не к бд прибита. БЛ прибивается к репе.
P>Это одно и то же, и в этом проблема. Я ж вам говорю, как можно иначе — но вы упорно видите только вариант из 90х-00х
Ты показал это "иначе", но там всё ещё хуже прибито. Вплоть до побуквенного сравнения текста sql.
P>В новом подходе не надо БЛ прибивать ни к какой репе, ни к бд, ни к стораджу, ни к кафе, ни к внешним сервисам
Ага-ага.
P>>>Шота я этого за 4 года не заметил
P>·>Может у тебя проекты написанные вайтишниками после курса ML, я не знаю. Но у тебя есть целый гитхаб, погляди насколько часто и для чего Object используют.
P>Я как раз с гитхаба и брал, если что.
Ссылку давай.
P>>>Юзеру так и скажете — мы не можем вернуть ваши деньги, потому что у нас в конфигурации возвраты отключены.
P>·>Для этого и есть L1 support — "проверьте, что ваш компьютер включен".
P>Я именно это сказал — L1 support так и скажет юзеру, "в конфиге отключено, значит неположено"
P>Что бы такого не случалось, в тестах должен быть сценарий, который включает возврат. И так для всех апи которые вы выставляете.
Не понял, если возврат отключен, то и тест должен тестировать, что возврат отключен.
P>>>Добавили, посмотрели дифом, вкомитали. Вам же не надо сразу всё обрабатывать.
P>·>А в дифе 10к строчек отличаются. И как это смотреть? Аудит же пишется для каждой операции, т.е. каждого теста, да ещё и не по разу.
P>А почему 10к а не 10к миллионов?
Примерное типичное кол-во сценариев реальной системе большего, чем хоумпейдж масштаба.
P>>>Если апи возвращает то, что надо, это значит что у вас связка конфиг-di-sl-рантайм-переменные-итд склеено правильно.
P>·>И это ты предлагаешь гонять на каждый "updateUser(newUser, oldUser)"? Спасибо, не надо нам такого щастя.
P>Да, я в курсе, у вас есть L1 суппорт, который скажет клиенту, что возвраты не положены.
P>Это не шутка — мне так L1 однажды залепил
P>Неделя бодания и перекинули проблему наверх, только когда я сослался на федеральный закон
P>Признавайтесь, ваша идея?
Только не пытайся доказать, что это у них "не работало", потому что тесты у них неправильные. Уж поверь, у них всё работало как надо (им).
P>>>Можно. Это старый подход.
P>·>Ты говоришь как будто это что-то плохое. Это разумный подход. Делить не по тому, что сейчас у фаулеров в моде, а по конкретному осязаемому критерию, т.к. это напрямую выражается во времени запуска и требуемых ресурсов для тестирования.
P>В данном случае вам нужно писать больше кода в тестах, и они будут хрупкими. Другого вы с моками не получите. Потому и убирают зависимости из БЛ целиком, что бы легче было покрывать тестами
Но ведь не "убирают", а переносят. Что добавляет и количество прод-кода и число тестов.
P>>>Это новый подход, позволяет обходиться без моков-стабов итд и свести тестирование ключевых вещей к дешовым юнит-тестам
P>·>У тебя тривиальное updateUser(newUser, oldUser) не тестируется юнитами. Любая мелочёвка требует запуска всего, в лучшем случае с in-mem субд.
P>Ага, сидим да годами ждём результаты одного теста. Вам самому не смешно?
Думаю ваш хоум-пейдж за час тестируется, в лучшем случае.
P>·>С такими же гарантиями можно и просто метод дёргать. Аннотации это только от плохого дизайна.
P>Ну вот подергали вы метод. А потом вас попросили отразить всё такое в сваггере каком, что бы другим было понятно. Гы-гы. Ищите строчки в коде.
P>А с аннотациями взял да и отрендерил манифест.
Гы-гы. У тебя же, ты сам говорил, что попало где попало — и в переменных окружения, и в конфигах и где угодно эти "аннотации" висят. Сваггер у вас каждые 5 минут новый, да?
P>>>Вы же не проверяете, что джава выполняет циклы правильно? Так и здесь
P>·>Фреймворк-ориентед программинг? Нет, спасибо.
P>Это ж классика — отделяем логику, которая меняется часто, от той, которая меняется редко. По этому пути индустрия идет последние 50 лет
Ты любишь сложность на пустом месте, притом в прод-коде, я уже понял. Но это плохо. Фреймворк это совсем другая весовая категория. Для того что ты пишешь достаточно extract method refactoring, а не новая архитектура с фреймворками.