I>Лично для меня разница, всё-таки, есть. Вот два примера: I>Казалось бы, действие одно и то же. Но тестировать второй вариант значительно проще, так как у нас есть контракт которому нужно соответствовать.
Согласен безусловно. Но у меня на практике этот подход работал только для чисто инфраструктурного кода, который по определению SRP.
Для бизнес-логики идея подыхает из-за комбинаторного взрыва.
Чтоб было понятно о чём речь. Простейший бизнес-сценарий дёргает сервисы расчёта стоимости заказа, учётную политику для конкретного контрагента, определение адресата по кладр и дальше передаёт результат в 5-7 других биз-сценариев, которые выбираются динамически и могут посылать по почте/печатать отчёт/запускать документоооборот и тыды и тыпы.
Даже для такой мелочёвки проще прокинуть один service locator, при необходимости дополняя DI-инъектором внутри классов, что-то типа serviceProvider.InjectAll(this).
В более сложных вещах, когда только краткая сопроводиловка в бумаге за 200 листов перелазит, микроменеджмент на уровне отдельных сервисов нереален в принципе.
На больших масштабах все эти "вы можете отследить каждую зависимость" превращается в "вы _будете_ отслеживать _каждую_ зависимость". Нафиг-нафиг.
I>Если же у нас по коду класса раскаданы вызовы GetService, то это неизменно приводит к тому что тесты сыпятся в рантайме, а это не есть хорошо. I>Для себя обозначил такое правило: "ServiceLocator не должен встречаться в тестируемом коде".
А такие штуки уже не ловятся классическими юнит-тестами в принципе, только интеграционными. Масштаб не тот слегка. Ну, как танкер в микроскоп проверять.
На практике вся разница в том, что мы не воссоздаём всё окружение для каждого теста в отдельности. Вместо этого поднимается инстанс сервиса с включенными отладочными ассертами и дальше он топится пачкой проверок, записанных в виде стандартных юнит-тестов. Как опция, сами тесты подгружаются в инстанс сервиса и используют внутреннее API сервиса, т.е. тот самый servicelocator.