All streams
Search
Write a publication
Pull to refresh
@Druuread⁠-⁠only

User

Send message
> Не «не надо», а незачем. Их поведение (если они покрыты тестами) предсказуемо, и они чаще всего не вносят собственный эффект в тест.

Давайте немного уточним, вот есть метод, у него нет зависимостей. Теперь мы какой-то из аргументов перенесли в поле класса (сделав зависимостью). В каком случае эта зависимость будет «функциональной», а в каком — нет?
> Только вам для этого надо знать, что БД — это неявный вход для этого метода.

Как я могу этого не знать, если согласно спецификации этот метод использует мапинг из бд?

> Вот только логика там есть даже в том рудиментарном варианте, который мной написан: из реквеста достается конкретное свойство, возвращается обработанный реквест, а не исходный.

И один единственный тест эту логику проверит. Вы же выше речь вели о том, что вам надо много сетапов, т.к. разные мапинги. Но в данном случае валидность метода от того, какой мапинг лежит в бд, вообще никак не отличается, если вы и напишете кучу тестов с разными мапингами (которые будут возвращаться из моков), то если один тест прошел — остальные практически гарантированно пройдут. Зачем тогда эти тесты нужны, и почему бы не перенести их в тестирование маппера, где это будет проще (т.к. туда все что надо передается рпотсо аргументом, это всегда удобнее чем настраивать моки, согласитесь)?

> Значит, нам нужен либо (еще один) враппер вокруг IMetadataProvider.GetMappingMetadataFor

Вроде, вы сами ответили на свой вопрос?
> Ну вот в моем опыте внутренних зависимостей с поведением чистой функции — подавляющее меньшинство

Так это уже вопрос исключительно вашей архитектуры. Никто же вам не мешает максимально выделять логику в чистые функции.

Кроме того, не совсем понятно, почему чистые зависимости мокать не надо, а «грязные» — надо. Почему такое разделение?
Конечно, надо — достаточно одного единственного теста, который вытягивает некоторые данные из бд и применяет некоторый маппинг. Если получилось — метод работает правильно. В итоге вам одного тестового сетапа и достаточно (о чем я выше говорил). А если вы хотите проверить именно правильность мапинга (или правильность взаимодействия с БД) — вы проверяете маппер (или провайдер), потому что это их ответственность, а не ответственность Request Map(Request).

Можно сказать тут, что любой тест для Request Map(Request) будет автоматически интеграционным, потому что сам метод единственное что делает — это обеспечивает интеграцию между двумя модулями, это метод-клей. Если вы в этом методе изолируете зависимости — то вы просто ничего не протестируете, за отсутствием какой-либо логики в данном методе.
Так мы в итоге и пришли к предлагаемому мной изначально варианту — мокать только внешние зависимости, т.к. все остальные — могут (и должны) быть функциональными.
Там методы генерируют спецификации. Исполняются спецификации уже отдельно.
> (ну то есть за исключением «чистых» функциональных зависимостей, конечно, но их тоже на моей памяти не мокают, ибо незачем, а значит, тоже за пределами обсуждения)

Когда я выше говорил про сервисы к БД с кучей зависимостей и методе-двустрочнике, который все что делает — это дергает пяток функций из них — то я как раз про функциональные зависимости и говорил. Оказывается, их «можно» и не мокать? Ну тогда в итоге кроме внешних сервисов и нечего мокать-то, как я и предложил изначально.
> Контракт SUT мне мешает.

Как он может мешать, если мы говорим о внутренней реализации функции? Сигнатура у нее та же самая, данные она принимает и возвращает те же. Просто логика мапинга выделена в метод, который мы и тестируем. Тестировать же надо логику, а не БД или работу моков.
Ну вот у вас метод _mapper.Map, его и тестируйте для проверки логики маппинга. Зачем вам при этом мокать _metadataProvider?
> А если у меня глобальный сетап, то мне нужно то ли взять откуда-то готовый SUT, то ли взять откуда-то зависимости, которые ему передать. Откуда?

Ну а как вы это делаете обычно? Через IoC-контейнер, я полагаю. Зарегистрировать/заменить моки для теста в IoC-контейнере вы можете откуда угодно.
> Нет, не нарушение.

С моей точки зрения — нарушение. У вас в одном методе смешана логика и доступ к хранилищу.
> Соответственно, эти ваши два метода — это хорошо, но они окажутся внутри SUT.

Если по смыслу они должны быть снаружи — то кто вам мешает их вынести?
> Технические ограничения не позволяют (я не зря про request filter написал).

Это как может быть? Один метод достает мапинг из хранилища и возвращает, второй — принимает то, что вернул предыдущий, и применяет.
> И все пять из них нужны для выполнения одной ответственности?

Да, для вполне конкретной и определенной задачи.

> Координаторов в системе мало.

Ну вот в моей практике все строго наоборот.
> Выделять логику дальше.

А некуда выделять. Все, что делает этот метод — дергает 5 других методов. Конечно, можно, например, разбить его так, чтобы было 2 метода по два вызова и один скомбинированный с тремя. Причем каждый из новых этих методов будет полностью бессмысленным, да и количество зависимостей тут не изменится.
> В спецификации написано «given mapping defined as follows»

Я буду передавать эти мапинги аргументом в данном случае.
> А вот как мне сделать, чтобы SUT использовал зависимости, которые используют другие зависимости, которые где-то потом неизвестно где используют эти моки?

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

Ну вот у вас и нарушение SRP — вы в одном методе и в хранилище лезете, и какую-то логику мапинга реализуете. Кто еще этот мапинг разбирает и смотрит, как по нему, с-но, мапить?
> Еще раз, по буквам. В каждом тесте я объявляю тот объект, который ему нужен. Один объект на тест. Суммарно k объектов. Я не объявляю все остальные объекты они мне не интересны.

Давайте подведем некоторый итог:

1. В вашем коде неким образом получается избегать большого количества зависимостей, не нарушая SRP, в моем — нет (например — у вас бд, бизнес-логика содержится в сервисах, их много, они разделены согласно доменной логике, какой-нибудь метод-двустрочник может использовать полдесятка разных зависимостей, как вы тут будете количество зависимостей снижать?)
2. У вас есть всякий indirect output, я его по возможности избегаю и стараюсь тестировать при помощи черного ящика.

Возможно, в _вашей_ ситуации юнит-тесты имеют смысл, в моей — очевидно, не совсем так.
> Читать «фреймворки для моков редко показывают примеры глобальных повторно используемых сетапов».

Я не могу понять, чем,, по-вашему, настройка глобального сетапа отличается от любого другого. Почему вы решили, что там есть какие-то особенности? Вызываются те же методы, с тем же результатом.

Information

Rating
Does not participate
Registered
Activity