Здравствуйте, Pauel, Вы писали:
P>>>Вы вот сами путаете моки и стабы
P>·>Ок, пусть. Не вижу, в чём важность этой терминологии. Я использую название "мок", потому что библиотека называется mockito и создаются эти штуки функцией mock или аннотацией @Mock. Если тебе комфортнее стаб, пусть. Хоть горшком назови, только в печку не ставь.
P>Моки изначально предназначались для тестов вида "вызываем вон то, вон так, в такой последовательности"
Может быть. Неясно какое это имеет значение сейчас, так исторические курьёзны. Даже если посмотреть на историю библиотек для тестов — за много лет много чего менялось и переделывалось.
P>>>Ну так в джаве и пишут — перемножают сущности и радуются.
P>·>Причём тут перемножают? Это диктуется требованиями. Если в json тебе нужен b64, а аналогичном месте protobuf тебе нужен Bytes, то хоть на bf пиши, у тебя будут комбинации.
P>У вас — охотно верю.
Потому что у нас не хелловорды, а не как у вас, да?
P>Я вам пример приводил, про время, вам он ожидаемо не понравился — язык не тот
Я не понял к чему ты скачешь с одного на другое. Обсуждали статью и MaitreD, потом crypto api, теперь вот ещё time api зачем-то...
P>>>Я портировал довольно много кода с джавы в тайпскрипт, и охренел от тамошних привычек.
P>·>Портировал это значит, как минимум, ты по ходу удалял гору легаси кода, совместимость с устаревшим, етс.
P>С чего бы портирование стало означать удаление легаси ?
С того. Когда код существует хотя бы десяток лет — там наслоения чего попало, когда что-то делалось и переделывалось, много накапливается мусора "по историческим причинам".
P>>>Не нужны никакие "9 комбинаций" — нужно отделить создание и представление.
P>·>Так в изначальном дизайне crypto так и было — создаём hmac нужного алгоритма, потом выводим в нужном представлении. Ты почему-то упаковал это в одну функцию и назвал успехом.
P>В данном случае мне не надо переживать за поломаные тесты, если понадобится другой алгоритм, другая либа, итд.
P>Вот понадобился не hmac а что другое — в файлике samples поменял десяток значений, и всё
Почему десяток? У тебя только десяток операций в api?
P>А ваша альтернатива этому — еще и тесты перебулшитить.
Один, скорее всего. Ибо одного теста достаточно чтобы зафиксировать логику вычисления hmac. В остальных тестах достаточно ассертить его наличие, но не конкретный формат.
P>·>У кого "у нас"? Если бы никому не требовались разные виды токенов в разном представлении, то в библиотеке crypto был бы "makeToken" с ровно одним парамом.
P>·>Такое ощущение, что ты говоришь о дизайне какой-то домашней странички, а не о сложной системе.
P>Ну да, этож только у вас сложные системы.
Ну да, сам же сказал, что у тебя всё помещается в один файлик. Или он гиговый?
P>>>Количество может быть уменьшено за счет подхода к дизайну.
P>·>Я не понял, разговор был о crypto, теперь на какой-то time-api переключился. Я за твоим полётом мысли не успеваю.
P>У вас любой из примеров вызывает какой то негатив
Какой негатив? Вроде говорили об одном, теперь чего-то новое.
Вообще неясно причём тут time api и причём тут моки и тестирование вообще.
P>>>А операция конверсии в прикладном коде будет вот такой DateTimeOffset.from({...date.toFields(), ...time.toFields, offset: serverOffset});
P>·>Это только на js годится такое писать. Со статической типизацией такое не прокатит.
P>Успокойтесь — это все статически контролируется, только в вашу джаву такие фичи еще не завезли.
Спасибо, но сводить всё к массиву из 7 чиселок — это фигня полная и издевательство. Даже такое
DateTimeOffset.from({...time.toFields, ...date.toFields(), offset: serverOffset}); — и всё поехало. И где наносекуды, интересно?
Конструкторы удобнее и надёжнее с нужными типами,
например,
OffsetDateTime.of(date, time, offset), это хотя бы читабельно, и если что-то не так, не компиляется.
P>>>А если вы решили понасоздавать N! комбинаций — удачи, внятного покрытия вам не видеть, как своих ушей, хоть с моками, хоть без них.
P>·>Я вроде рассказал, как упрощать тестирование комбинаций.
P>Вы уже показали — перебулшитить все тесты, когда можно ограничиться десятком строчек на весь проект.
Это твои фантазии.
P>>>Читайте себя внимательно — вы регулярно утверждаете, что именно у меня проблемы с моками, что именно у меня квалификация под сомнением.
P>·>Так ты сам откровенно пишешь: "за 20 лет индустрия так и не осилила". Я сталкивался с другой индустрией, в которой с моками (или стабами?) проблем таких нет.
P>Ну да — для вас перебулшитить тесты проблемой не является
Еще и настаиваете, что так и надо.
Я настаиваю, что так не надо.
P>>>Именно — так не надо, но именно так пишут и это типичный пример, к сожалению
P>·>Может в твоей индустрии. В java так не пишут, ну если только совсем вчерашние студенты, но PR такое не пройдёт.
P>Проходит же. Вот я и интересуюсь, кто настрочил горы непотребства 
Вчерашние студенты?
P>>>Интеграционные тесты это все выше уровня простых юнит тестов. Далеко не все интеграционные автоматически медленные. Условно, чистая функция вызывает десяток других чистых — опаньки, тест такой штуки будет интеграционным. Но нам это по барабану — они быстрые, можно обзапускаться хоть до посинения.
P>·>Ты куда-то мимо пошел. Не хочу вдаваться в подробности терминологии юнит-инт. Суть в том, что в твоём предложенном тесте появляется connectionString, значит "приходится плодить медленные тесты и тривиальные ошибки обнаруживать только после запуска всего приложения".
P>Эта разновидность тестов нужна и вам.
Нужны, но не для проверки каждой строчки кода, что параметры вызова не перепутаны. А только для тестирования интеграции.
P>>>Наоборот. Большое количество дешовых тестов, тысячи минимум, и десятки-сотни интеграционных, самых тяжелых тестов по одному на каждый сценарий приложения — десяток другой.
P>·>Какой тесто обнаружит ошибку в коде "repository.updateUser(newUser, oldUser)" и как? Вот это "выполним операцию и проверим, что состояние юзера соответствует ожиданиям"? Что должно быть поднято для прогона такого теста?
P>да вобщем то ничего, какая нибудь ин-мемори дб и инстанц контроллера или юз-кейса.
Ясно, закопайте.
P>·>Под интеграцией я понимал в данном случае твоё "curl -X POST". Это плохой тест, медленный, неуклюжий. Число таких тестов надо стараться минимизировать.
P>Такие тесты нужны в любом случае, моки-стабы от них не избавляют, это иллюзия.
Я знаю, что нужны, Я написал, что "
Число таких тестов надо стараться минимизировать".
P>>>В огороде бузина, а в киеве дядька. При чем здесь require ? framework as a detail и clean architecture это подходы к дизайну, архитектуре.
P>·>В том, что в твоём коде jest подменял код внутри глобального реестра require.
P>Я вам пример привел, как применяют моки. Обмокать можно что угодно, в т.ч. и в джаве-дотнете
Я не знаю кто так применяет, но так делать не надо.
P>>>Неверно — тестируется не код, а соответствие ожиданиям, требованиями. какой бы дизайн у вас ни был — все равно нужны тесты апи, сценариев итд.
P>·>Опять буквоедство какое-то. Что по-твоему тестируется на соответствие ожиданиям, требованиям?
P>Продукт, система, приложение, апи, компонент, модуль. Для теста именно кода у нас другие инструменты — код-ревью, линт, дизайн-ревью, статические анализаторы, итд.
Я сказал "Они отменяют необходимость написания тучи этих самых xxxComposition, нет кода — нечего тестировать". Ты прикопаться решил к слову код? Ок, пусть будет не код, а модуль-компонент.
"Моки отменяют необходимость написания тучи этих самых xxxComposition, нет такого компонента|модуля — нечего тестировать." Так яснее?
P>>>А вы тут сказки рассказыете, что это делать не надо
P>·>Суть в том, что тесты апи можно тестировать без реальной субд|кафки и т.п. И описывать ожидания, что updateUser сделан именно с (newUser, oldUser), а не наоборот.
P>Можно. И это делается без моков. Если мы заложимся на значение или состояние, то получим куда больше гарантий.
Без моков ты предложил только полный запуск всей аппликухи, в лучшем случае с тестовой субд. Kafka/amps/lbm/solace/tibco/etc, кстати, тоже тестовую будешь пускать? Или как?
P>В функции средний девелопер может понаделывать ошибок куда больше, чем перепутать old и new.
Я в этом и до среднего не дотягиваю, дохрена таких ошибок делаю, но вся эта фигня на раз ловится тестами, c моками (стабами), да.
P>>>Покажите как вы в репозиторий метод getAll передаете фильтры, сортировку итд
P>·>Не знаю, не припомню где у нас есть такое. Но наверное был бы какой-нибдуь value object, который передаёт необходимые настройки фильтров и сортировок.
P>Вот вы и встряли
Чем лучше изолируете, тем больше вам тестировать. Тут помогло бы использование какого dsl. В том же дотнете есть такое, и всё равно надо думать, что передать в репозиторий, быть в курсе, съест ли тамошний провайдер конкретную функцию или нет.
Пофиг. Я не знаю о чём ты говоришь и делаю wild guesses.
P>>>Именно — кто даст гарантию что с тем или иным конфигом, рантаймом, переменными окружения, тот самый метод контролера не начнет вдруг гарантировано валиться ?
P>·>Никто.
P>Именно! А потому нам все контроллеры нужно тестировать в апи тестах — тем самым мы исключаем добрый десяток классов проблем.
И эти тесты дадут тебе гарантию?
P>Что вас смущает? deep.eq проверит всё, что надо. query это не строка, объект с конкретной структурой, чтото навроде
P>P>{
P> sql: 'select * from users where id=?',
P> params: [id],
P> transformations: {
P> in: [fn1],
P> out: [fn2]
P> }
P>}
P>
Жуть. Ну ладно. Т.е. тут мы тестируем репозиторий и ассертим текст sql

Как проверить, что текст запроса хотя бы синтаксически корректен? И что он при выполнении выдаст то, что ожидается? И как ты собрался тут подменять субд? Ты обещал, что теперь эту хрень можно отдать любой db и оно выдаст одинаковый результат? Даже если эта субд это oracle или cassandra? Да там синтаксис банально другой.
P>Сами трансформации тестируются отдельно, обычными юнитами, например expect(fn1(user)).to.eq(user.id);
Так ведь надо трансформировать не некий user, а конкретно ResultSet возвращённый из "select *". Что колоночки в select местами не перепутаны, как минимум.
Ещё это всё "красиво" только на твоих хоумпейдж проектах. В реальном коде эти sql будут сотни строк с многоэтажными джойнами и подзапросами, и такие "тесты" станут даже немножечко вредить.
P>>>вот, вы начинате понимать, для чего нужны интеграционные
Здесь вам понадобится тест компонента с подклееной реальной бд. И без этого никак.
P>·>Т.е. та же ж, вид в профиль, но теперь большинство логики без реальной бд не протестировать. В случае с репо реальная бд нужна только для тестирования самого слоя взаимодействия с бд, а остальное может мокаться (стабиться?). Ты же предлагаешь всё приложение тестировать с реальной бд.
P>Вы все думаете в единицах старого дизайна, когда БЛ прибита гвоздями к бд.
Не к бд прибита. БЛ прибивается к репе.
P>>>Это типичный пример интеграция — вы соединяете выходы одного со входами другого.
P>·>Ну да. Но это не означает, что для этого необходимо тестировать только с реальной бд.
P>Нам нужна любая бд, что прогонять некоторые тесты, обычно небольшое количество.
Любая бд даёт любой результат.
P>>>Это в любом случае необходимо — у контролера всегда хрензнаетсколькилион зависимостей прямых и косвенных, и чтото да может пойти не так.
P>·>Для этого и объединяют толпу зависимостей в одну. Чтобы не N! было.
P>Объединяйте что угодно — а контролер все равно придется вызвать в АПИ тестах.
Не знаю что за апи тесты ты тут имеешь в виду, предполагаю, что это твой "curl". Если так, то достаточно позвать один метод для проверки интеграции всех компонент, а не для тестирования всей бизнес-логики апи.
P>>>А там где используют object, то отличий от js никакого нет
P>·>Ну обычно object стараются избегать использовать.
P>Шота я этого за 4 года не заметил 
Может у тебя проекты написанные вайтишниками после курса ML, я не знаю. Но у тебя есть целый гитхаб, погляди насколько часто и для чего Object используют.
P>>>Иначе есть шанс что тот самый роут в нужный момент не сможет быть вызван, т.к. он просто задизаблен в конфиге
P>·>Не понял, ну раз задизаблен, значит и нельзя вызвать. Это является не ошибкой, а конфигурацией системы. Неясно что тут в принципе тестировать.
P>Юзеру так и скажете — мы не можем вернуть ваши деньги, потому что у нас в конфигурации возвраты отключены.
Для этого и есть L1 support — "проверьте, что ваш компьютер включен".
P>>>Вы там что, на каждый коммит всю систему переписываете?
P>·>Я описываю ситуацию — добавили новое общее поле в аудит — везде в этих твоих логах каждого теста — строчка аудита выглядит чуть по-другому.
P>Добавили, посмотрели дифом, вкомитали. Вам же не надо сразу всё обрабатывать.
А в дифе 10к строчек отличаются. И как это смотреть? Аудит же пишется для каждой операции, т.е. каждого теста, да ещё и не по разу.
P>>>Апи это именно про интеграцию — вызов контроллера в конкретном окружении, что есть в чистом виде интеграция, т.к. у контроллера всегда есть хрензнаетсколькилион зависимостей, прямых и косвенных.
P>·>Апи это про интерфейс системы. Интеграция тут причём?
P>Если апи возвращает то, что надо, это значит что у вас связка конфиг-di-sl-рантайм-переменные-итд склеено правильно.
И это ты предлагаешь гонять на каждый "updateUser(newUser, oldUser)"? Спасибо, не надо нам такого щастя.
P>>>Старый подход — контролер вызывает сервис БД который вызывает БЛ через репозиторий итд. Моками надо обрезать зависимости на БД у БЛ.
P>>>Т.е. БЛ это клиент к БД, по факту.
P>·>Моками (стабами?) обрезается БД и прочие внешние вещи от БЛ. Чтобы при тестировании БЛ можно было быстро тестировать логику кода, без всяких сетевых соединений и запуска всего приложения.
P>Можно. Это старый подход.
Ты говоришь как будто это что-то плохое. Это разумный подход. Делить не по тому, что сейчас у фаулеров в моде, а по конкретному осязаемому критерию, т.к. это напрямую выражается во времени запуска и требуемых ресурсов для тестирования.
P>·>Да пофиг. Эти слои можно жонглировать как сейчас модно. Это меняется каждый год.
P>Это новый подход, позволяет обходиться без моков-стабов итд и свести тестирование ключевых вещей к дешовым юнит-тестам
У тебя тривиальное updateUser(newUser, oldUser) не тестируется юнитами. Любая мелочёвка требует запуска всего, в лучшем случае с in-mem субд.
P>>>>>Кое что надо и в самом методе вызывать, без этого работать не будет.
P>>>·>Именно! И накой тогда аннотация нужна для этого?
P>>>Базовые гарантии. Некоторые из них можно выключить или доопределить конфигом итд.
P>·>Базовые гарантии чего?
P>Например, если вы аннотацией указываете что метод работает из под другого юзера, например Freemium, то базовая гарантия — вы будете получать Freemium юзера внутри этого метода. Ее можно модифицировать — отключить весь Freemium в конфиге приложения. Или навесить на Freemium юзера доп.свойства — свежегенеренное имя-емейл-баланс.
С такими же гарантиями можно и просто метод дёргать. Аннотации это только от плохого дизайна.
P>>>Разумеется, это интеграция — что аудит интегрирован с тем или иным стораджем. 1 тест.
P>·>"для данных сценариев записываются нужная инфа". Это где-то нужно валидировать, что для некой бизнес-операции в соответвтующих условиях записывается соответвтующий требованиям сообщение аудита.
P>В этом случае можно сделать аудит через тесты состояния. Прогоняем операцию, сравниваем что в аудите. Тесты вида "вызываем аудит с параметрам" — это тесты "как написано"
Не "вызываем аудит с параметрам", а "послано такое-то сообщение в аудит".
P>·>Как я понял скорее всего разница в том, что я обычно пишу на статике. Аннотации мешают тем, что их сложнее тестировать, контролировать типы. Приходится вместо простых вызовов методов поднимать очень много компонент и смотреть, что процессоры аннотаций сработали правильно. Т.е. вместо того, чтобы просто вызвать метод, мы пишем кучу слоёв какого-то мусора, чтобы вызывать ровно тот же метод.
P>Вот эти вещи нужно выталкивать во фремворк, что бы там протестировать раз на все времена, и не надо было каждый раз перепроверять "а не отвалился ли процессор аннотации"
P>Вы же не проверяете, что джава выполняет циклы правильно? Так и здесь
Фреймворк-ориентед программинг? Нет, спасибо.