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

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 тест.

·>"для данных сценариев записываются нужная инфа". Это где-то нужно валидировать, что для некой бизнес-операции в соответвтующих условиях записывается соответвтующий требованиям сообщение аудита.

В этом случае можно сделать аудит через тесты состояния. Прогоняем операцию, сравниваем что в аудите. Тесты вида "вызываем аудит с параметрам" — это тесты "как написано"

·>Как я понял скорее всего разница в том, что я обычно пишу на статике. Аннотации мешают тем, что их сложнее тестировать, контролировать типы. Приходится вместо простых вызовов методов поднимать очень много компонент и смотреть, что процессоры аннотаций сработали правильно. Т.е. вместо того, чтобы просто вызвать метод, мы пишем кучу слоёв какого-то мусора, чтобы вызывать ровно тот же метод.


Вот эти вещи нужно выталкивать во фремворк, что бы там протестировать раз на все времена, и не надо было каждый раз перепроверять "а не отвалился ли процессор аннотации"
Вы же не проверяете, что джава выполняет циклы правильно? Так и здесь
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.