Здравствуйте, ·, Вы писали:
P>>Вы вот сами путаете моки и стабы
·>Ок, пусть. Не вижу, в чём важность этой терминологии. Я использую название "мок", потому что библиотека называется mockito и создаются эти штуки функцией mock или аннотацией @Mock. Если тебе комфортнее стаб, пусть. Хоть горшком назови, только в печку не ставь.
Моки изначально предназначались для тестов вида "вызываем вон то, вон так, в такой последовательности"
P>>Ну так в джаве и пишут — перемножают сущности и радуются.
·>Причём тут перемножают? Это диктуется требованиями. Если в json тебе нужен b64, а аналогичном месте protobuf тебе нужен Bytes, то хоть на bf пиши, у тебя будут комбинации.
У вас — охотно верю. Я вам пример приводил, про время, вам он ожидаемо не понравился — язык не тот
P>>Я портировал довольно много кода с джавы в тайпскрипт, и охренел от тамошних привычек.
·>Портировал это значит, как минимум, ты по ходу удалял гору легаси кода, совместимость с устаревшим, етс.
С чего бы портирование стало означать удаление легаси ?
P>>Не нужны никакие "9 комбинаций" — нужно отделить создание и представление.
·>Так в изначальном дизайне crypto так и было — создаём hmac нужного алгоритма, потом выводим в нужном представлении. Ты почему-то упаковал это в одну функцию и назвал успехом.
В данном случае мне не надо переживать за поломаные тесты, если понадобится другой алгоритм, другая либа, итд.
Вот понадобился не hmac а что другое — в файлике samples поменял десяток значений, и всё
А ваша альтернатива этому — еще и тесты перебулшитить.
·>У кого "у нас"? Если бы никому не требовались разные виды токенов в разном представлении, то в библиотеке crypto был бы "makeToken" с ровно одним парамом.
·>Такое ощущение, что ты говоришь о дизайне какой-то домашней странички, а не о сложной системе.
Ну да, этож только у вас сложные системы.
P>>Количество может быть уменьшено за счет подхода к дизайну.
·>Я не понял, разговор был о crypto, теперь на какой-то time-api переключился. Я за твоим полётом мысли не успеваю.
У вас любой из примеров вызывает какой то негатив
P>>А операция конверсии в прикладном коде будет вот такой DateTimeOffset.from({...date.toFields(), ...time.toFields, offset: serverOffset});
·>Это только на js годится такое писать. Со статической типизацией такое не прокатит.
Успокойтесь — это все статически контролируется, только в вашу джаву такие фичи еще не завезли.
P>>А если вы решили понасоздавать N! комбинаций — удачи, внятного покрытия вам не видеть, как своих ушей, хоть с моками, хоть без них.
·>Я вроде рассказал, как упрощать тестирование комбинаций.
Вы уже показали — перебулшитить все тесты, когда можно ограничиться десятком строчек на весь проект.
P>>Читайте себя внимательно — вы регулярно утверждаете, что именно у меня проблемы с моками, что именно у меня квалификация под сомнением.
·>Так ты сам откровенно пишешь: "за 20 лет индустрия так и не осилила". Я сталкивался с другой индустрией, в которой с моками (или стабами?) проблем таких нет.
Ну да — для вас перебулшитить тесты проблемой не является

Еще и настаиваете, что так и надо.
P>>Именно — так не надо, но именно так пишут и это типичный пример, к сожалению
·>Может в твоей индустрии. В java так не пишут, ну если только совсем вчерашние студенты, но PR такое не пройдёт.
Проходит же. Вот я и интересуюсь, кто настрочил горы непотребства
P>>Интеграционные тесты это все выше уровня простых юнит тестов. Далеко не все интеграционные автоматически медленные. Условно, чистая функция вызывает десяток других чистых — опаньки, тест такой штуки будет интеграционным. Но нам это по барабану — они быстрые, можно обзапускаться хоть до посинения.
·>Ты куда-то мимо пошел. Не хочу вдаваться в подробности терминологии юнит-инт. Суть в том, что в твоём предложенном тесте появляется connectionString, значит "приходится плодить медленные тесты и тривиальные ошибки обнаруживать только после запуска всего приложения".
Эта разновидность тестов нужна и вам.
P>>Наоборот. Большое количество дешовых тестов, тысячи минимум, и десятки-сотни интеграционных, самых тяжелых тестов по одному на каждый сценарий приложения — десяток другой.
·>Какой тесто обнаружит ошибку в коде "repository.updateUser(newUser, oldUser)" и как? Вот это "выполним операцию и проверим, что состояние юзера соответствует ожиданиям"? Что должно быть поднято для прогона такого теста?
да вобщем то ничего, какая нибудь ин-мемори дб и инстанц контроллера или юз-кейса.
P>>·>Ага-ага. Но тогда нужны ещё более медленные и неуклюжие интеграционные тесты, много
P>>Интеграционные всех уровней нужны всегда. Их количество определяется
P>>1. апи
P>>2. сценариями
P>>Большой апи — будет много тестов апи, иначе никак.
P>>Много сценариев — будет много тестов e2e, и этого тоже не избежать.
·>Под интеграцией я понимал в данном случае твоё "curl -X POST". Это плохой тест, медленный, неуклюжий. Число таких тестов надо стараться минимизировать.
Такие тесты нужны в любом случае, моки-стабы от них не избавляют, это иллюзия.
P>>В огороде бузина, а в киеве дядька. При чем здесь require ? framework as a detail и clean architecture это подходы к дизайну, архитектуре.
·>В том, что в твоём коде jest подменял код внутри глобального реестра require.
Я вам пример привел, как применяют моки. Обмокать можно что угодно, в т.ч. и в джаве-дотнете
P>>·>Они отменяют необходимость написания тучи этих самых xxxComposition, нет кода — нечего тестировать.
P>>Неверно — тестируется не код, а соответствие ожиданиям, требованиями. какой бы дизайн у вас ни был — все равно нужны тесты апи, сценариев итд.
·>Опять буквоедство какое-то. Что по-твоему тестируется на соответствие ожиданиям, требованиям?
Продукт, система, приложение, апи, компонент, модуль. Для теста именно кода у нас другие инструменты — код-ревью, линт, дизайн-ревью, статические анализаторы, итд.
P>>А вы тут сказки рассказыете, что это делать не надо
·>Суть в том, что тесты апи можно тестировать без реальной субд|кафки и т.п. И описывать ожидания, что updateUser сделан именно с (newUser, oldUser), а не наоборот.
Можно. И это делается без моков. Если мы заложимся на значение или состояние, то получим куда больше гарантий.
В функции средний девелопер может понаделывать ошибок куда больше, чем перепутать old и new.
P>>Покажите как вы в репозиторий метод getAll передаете фильтры, сортировку итд
·>Не знаю, не припомню где у нас есть такое. Но наверное был бы какой-нибдуь value object, который передаёт необходимые настройки фильтров и сортировок.
Вот вы и встряли

Чем лучше изолируете, тем больше вам тестировать. Тут помогло бы использование какого dsl. В том же дотнете есть такое, и всё равно надо думать, что передать в репозиторий, быть в курсе, съест ли тамошний провайдер конкретную функцию или нет.
P>>Именно — кто даст гарантию что с тем или иным конфигом, рантаймом, переменными окружения, тот самый метод контролера не начнет вдруг гарантировано валиться ?
·>Никто.
Именно! А потому нам все контроллеры нужно тестировать в апи тестах — тем самым мы исключаем добрый десяток классов проблем.
P>>P>>expect(query).to.deep.eq(pattern)
P>>
·>Ты не ответил ни на один заданный вопрос. Напомню: этот самый query был "select * from users where id=? + параметры + трансформации".
Что вас смущает? deep.eq проверит всё, что надо. query это не строка, объект с конкретной структурой, чтото навроде
{
sql: 'select * from users where id=?',
params: [id],
transformations: {
in: [fn1],
out: [fn2]
}
}
Сами трансформации тестируются отдельно, обычными юнитами, например
expect(fn1(user)).to.eq(user.id);
P>>вот, вы начинате понимать, для чего нужны интеграционные
Здесь вам понадобится тест компонента с подклееной реальной бд. И без этого никак.
·>Т.е. та же ж, вид в профиль, но теперь большинство логики без реальной бд не протестировать. В случае с репо реальная бд нужна только для тестирования самого слоя взаимодействия с бд, а остальное может мокаться (стабиться?). Ты же предлагаешь всё приложение тестировать с реальной бд.
Вы все думаете в единицах старого дизайна, когда БЛ прибита гвоздями к бд.
P>>Это типичный пример интеграция — вы соединяете выходы одного со входами другого.
·>Ну да. Но это не означает, что для этого необходимо тестировать только с реальной бд.
Нам нужна любая бд, что прогонять некоторые тесты, обычно небольшое количество.
P>>Это в любом случае необходимо — у контролера всегда хрензнаетсколькилион зависимостей прямых и косвенных, и чтото да может пойти не так.
·>Для этого и объединяют толпу зависимостей в одну. Чтобы не N! было.
Объединяйте что угодно — а контролер все равно придется вызвать в АПИ тестах.
P>>А там где используют object, то отличий от js никакого нет
·>Ну обычно object стараются избегать использовать.
Шота я этого за 4 года не заметил
P>>Иначе есть шанс что тот самый роут в нужный момент не сможет быть вызван, т.к. он просто задизаблен в конфиге
·>Не понял, ну раз задизаблен, значит и нельзя вызвать. Это является не ошибкой, а конфигурацией системы. Неясно что тут в принципе тестировать.
Юзеру так и скажете — мы не можем вернуть ваши деньги, потому что у нас в конфигурации возвраты отключены.
P>>Вы там что, на каждый коммит всю систему переписываете?
·>Я описываю ситуацию — добавили новое общее поле в аудит — везде в этих твоих логах каждого теста — строчка аудита выглядит чуть по-другому.
Добавили, посмотрели дифом, вкомитали. Вам же не надо сразу всё обрабатывать.
P>>Апи это именно про интеграцию — вызов контроллера в конкретном окружении, что есть в чистом виде интеграция, т.к. у контроллера всегда есть хрензнаетсколькилион зависимостей, прямых и косвенных.
·>Апи это про интерфейс системы. Интеграция тут причём?
Если апи возвращает то, что надо, это значит что у вас связка конфиг-di-sl-рантайм-переменные-итд склеено правильно.
P>>Старый подход — контролер вызывает сервис БД который вызывает БЛ через репозиторий итд. Моками надо обрезать зависимости на БД у БЛ.
P>>Т.е. БЛ это клиент к БД, по факту.
·>Моками (стабами?) обрезается БД и прочие внешние вещи от БЛ. Чтобы при тестировании БЛ можно было быстро тестировать логику кода, без всяких сетевых соединений и запуска всего приложения.
Можно. Это старый подход.
P>>В новом подходе БЛ, модель не имеет зависимости ни на репозиторий, на на БД. А раз так, то и моки не нужны.
P>>Т.е. в центре у нас БЛ, модель, а вызывающий код является её клиентом, и именно там зависимости на БД итд.
P>>Т.е. у нас слои поменялись местами.
·>Да пофиг. Эти слои можно жонглировать как сейчас модно. Это меняется каждый год.
Это новый подход, позволяет обходиться без моков-стабов итд и свести тестирование ключевых вещей к дешовым юнит-тестам
P>>>>Кое что надо и в самом методе вызывать, без этого работать не будет.
P>>·>Именно! И накой тогда аннотация нужна для этого?
P>>Базовые гарантии. Некоторые из них можно выключить или доопределить конфигом итд.
·>Базовые гарантии чего?
Например, если вы аннотацией указываете что метод работает из под другого юзера, например Freemium, то базовая гарантия — вы будете получать Freemium юзера внутри этого метода. Ее можно модифицировать — отключить весь Freemium в конфиге приложения. Или навесить на Freemium юзера доп.свойства — свежегенеренное имя-емейл-баланс.
P>>Разумеется, это интеграция — что аудит интегрирован с тем или иным стораджем. 1 тест.
·>"для данных сценариев записываются нужная инфа". Это где-то нужно валидировать, что для некой бизнес-операции в соответвтующих условиях записывается соответвтующий требованиям сообщение аудита.
В этом случае можно сделать аудит через тесты состояния. Прогоняем операцию, сравниваем что в аудите. Тесты вида "вызываем аудит с параметрам" — это тесты "как написано"
·>Как я понял скорее всего разница в том, что я обычно пишу на статике. Аннотации мешают тем, что их сложнее тестировать, контролировать типы. Приходится вместо простых вызовов методов поднимать очень много компонент и смотреть, что процессоры аннотаций сработали правильно. Т.е. вместо того, чтобы просто вызвать метод, мы пишем кучу слоёв какого-то мусора, чтобы вызывать ровно тот же метод.
Вот эти вещи нужно выталкивать во фремворк, что бы там протестировать раз на все времена, и не надо было каждый раз перепроверять "а не отвалился ли процессор аннотации"
Вы же не проверяете, что джава выполняет циклы правильно? Так и здесь