Здравствуйте, ·, Вы писали:
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({...})