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

P>>"деталь реализации" означает что разница в свойствах несущественна и инструменты взаимозаменяемы, т.к. эквивалентны

·>Да. Верно. Вместо "дёрнуть метод" — "вернуть данные, которые будут переданы методу"

Это и есть проблема. В новой версии кода например некому будет возвращать, и некому передавать, при полном соответствии с требованиям.
А вот тесты стали красными. Гы-гы.
И если код меняется часто, в силу изменения требований, вам надо каждый раз строчить все тесты с нуля.

Вот пример — у нас есть требование вернуть hash токен что бы по контенту можно было находить метадату итд
Мокист-джедай на полном серьезе мокает
1 импорт — убеждается что импортируется именно тот самый класс из той самой либы
2 класс — что бы мокнуть метод и проверяет, что переданы те самые параметры
3 метод hash — что бы мокнуть другой метод, убеждается, что в него приходят те самые значения
4 метод digest, что бы получить значение
и проверяет, что полученное значение и есть то, что было выдано digest

кода получается вагон и маленькая тележка

А теперь фиаско — в либе есть уязвимость и проблема с перформансом, и её надо заменить, гы-гы все тесты на моках ушли на помойкку

А если делать иначе, то юнит тестом покрываем вычисления токена — передаём контент и для него получаем тот самый токен.
Теперь можно либу менять хоть по сто раз на дню, тесты это никак не меняет

и кода у нас ровно один короткий тест, который вызывается с двумя-тремя десятками разных вариантов параметров, из которых большая часть это обработка ошибок, граничных случаев итд итд

P>>То есть, это инструменты которые решают разные классы задач — вместо "assert x = y" тестируем "унутре вызвали вон тот метод с такими параметрами"

·>"verify(mock).x(y)"

Вместо просто assert x = y вам надо засетапить мок и надеяться, что новые требования не сломают дизайн вашего решения.

P>>Собственно, уже 20 лет как известно, что особенностью тестов на моках является их хрупкость, т.к. привязываемся буквально к "как написано"

·>Это твои заморочки.

Вы чуть ниже сами об этом же пишете. Тесты на моках это те самые вайт бокс тесты, принципиально. И у них известный набор проблем, среди которых основной это хрупкость.

P>>Есть два подхода к покрытию — на моках, и классический. У каждого есть и достоинства, и недостатки.

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

Проблема простая — из тех проектов, что попадают ко мне, хоть опенсорс, хоть нет, в большинстве случаев тесты на моках или бесполезны, и толку нет, или дырявые, и надо фиксить, или вносят путаницу из за объема кода, и это тоже надо фиксить, или требования меняются радикально, а значит смена дизайна, и это снова надо фиксать
А вот если в проекте пошли по пути классического юнит-тестирования, то как правило тесты особого внимания не требуют — все работает само.

·>И ты тут телегу впереди лошади поставил. Ну да, у нас есть дизайн с side effects — что ж, либо давайте всё переписывать на хаскель, либо просто заюзаем моки для тестирования. У тебя есть третий вариант?


При чем здесь сайд эффекты?

P>>·>Ты так и не показал как ты предлагаешь решать эту проблему, только заявил, что решается одной строчкой, но не показал как. Проигнорировал вопрос дважды: Напиши однострочный интеграционный тест для tryAcceptComposition.

P>>Однострочный интеграционный код для tryAcceptCompositio это просто вызов самого контроллера верхнего уровня.
·>Проигнорировал вопрос трижды: Напиши однострочный интеграционный тест для tryAcceptComposition. Код в студию!

expect(new class().tryTryAcceptComposition(parameter)).to.eq(value);



P>>Так уже. Это ж вы почемуто считаете что моки делают иерархию плоской, и аргументов не приводите.

·>Где я так считаю? Моки ничего сами не делают. Это инструмент тестирования.

Вот некто с вашего акканута пишет

Ну так внедрение зависимостей DI+CI это и есть плоская иерархия.



P>>Это принцип direct mapping, к ооп он имеет опосредованное отношение. Как вы будете сами сущности моделировать — дело десятое. Городить классы сущностей — нужно обоснование

·>Ок. Могу согласится, что это дело вкуса. Не так важно класс это или лямбда. Суть моего вопроса по статье — как же писать тесты, чтобы не оставалось непокрытого кода.

Нету такой задачи покрывать код. Тестируются ожидания пользователя, соответствие требованиями, выявление особенностей поведения и тд.

P>>Какой именно код не протестирован?

·>функция tryAcceptComposition. Ты обещал привести однострочный тест, но до сих пор не смог.

Мне непонято что в моем объяснении вам не ясно

P>>·>Ну так внедрение зависимостей DI+CI это и есть плоская иерархия. В конструкторе все зависимости, методы — целевая бизнес-логика. В статье это и было показано, что такой подход эквивалентен частичному применению функций — код под капотом идентичный получается.

P>>Вам для моков нужно реализовывать в т.ч. неявные зависимости. Если вы делаете моками плоску структуру, получаются тесты "проверим что вызвали вон тот метод" т.е. "как написано"
·>Это называется whitebox тестирование. Причём тут моки?

Браво — вы вспомнили про вайтбокс. Моки это в чистом виде вайтбокс, я это вам в прошлый раз говорил раз десять
А следовательно, у моков есть все недостатки, характерные для вайтбокс
Первая ссылка в гугле:
Expensive
If the code base is changing quickly, automated test cases are useless
Incomplete cases
Time consuming
More errors

А вот если вы идете методом блакбокс тестирования, то никакие моки вам применить не удастся, и это дает более устойчивый код решения и более устойчивые тесты

P>>А если мокаете клиент БД или саму бд, то вам надо под тест сконструировать пол-приложения.

·>Не очень понял что именно ты имеешь в виду. Вот мы тут вроде статью обсуждаем, там есть код, вот покажи на том коде что не так и как сделать так.

Уже объяснил. Что именно вам непонятно?

·>А конкретно? С примерами кода. Как эти ожидания выражаются? Почему "вернуть X" — ты называешь "ожидание пользователя", а "вызвать x()" — "протокол взаимодействия"? И что всё эти термины значат? В чём принципиальная разница?


Например, сделали другой дизайн решения, например, отказались от сущности MaitreD, и всё ваше на моках сломано.
А вот простые тесты на вычисления резервирования остаются, потому как ни на какой MaitreD не завязаны. Что будет вместо MaitreD — вообще дело десятое.

P>>·>Слова Responsibility и Actor — это из словаря FRD. Т.е. именно эта терминология используется бизнесом для общения с девами.

P>>Успокойтесь. Добавлять классы на основании разговора на митинге — дело так себе. Актор может вообще оказаться целой подсистемой, а может и наколеночным воркером, или даже лямда-функцией
·>Ок. Каким образом ты делаешь соответствие термина в FRD с куском кода?

Выбираю абстракцию наименьшего размера, которая покрывает кейс, и которую я могу протестировать

P>>У вас видение из 90х или 00х, когда аннотациями лепили абы что.

·>А что сейчас? Сделай show&tell, или хотя бы ссылку на.

Я уже показывал что в прошлый раз, что в этот — отлистайте да посмотрите. Это ваша проблема что вы умеете только свойства инжектать да конструкторы лепить
Вы в очередной раз просто обесцениваете, а потом просите что бы я показал вам тож самое еще раз

P>>Ровно наоборот — аннотации в покрытии учавствуют, просто обязаны.

·>Покажи мне coverage report, где непокрытые аннотации красненьким подсвечены.

Expectation failed: ControllerX tryAccept to have metadata {...}


P>>Прикрутили метаданные — есть тест на это. Используются ли эти метаданные — тоже есть тест.

·>Покажи как выглядит тест на то, что аннотация повешена корректно.

const tryAccept = Metadata.from(ControllerX, 'tryAccept')

expext(tryAccept).metadata.to.match({...})
Отредактировано 03.12.2023 18:48 Pauel . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.