Какие цели преследует Dependency Injection?
DI это способ создать интерфейсы там, где их не было ранее, но они вдруг понадобились сейчас. Интерфейсы вводятся не просто так, а для решения какой-либо задачи. Отойдя от программирования и взяв в качестве примера ситуацию с аппаратным обеспеченим, то мы поймем, что люди очень сильно выиграли когда решили разделить вычислительные средства на материнская плата, ЦПУ, ОЗУ, Жесткий диск и др. Да, они усложнили введя интерфейсы, но при этом повысилось удобство эксплуатации и возрасла скорость разработки. Скорость изготовления частей возрасло за счет того что отдельный компонент изготовить проще, чем целую систему! Более того компонент может быть с разными характеристиками, ценою и изготавливаться многими компаниями на различных производственных мощностях. Возвращаясь к DI : программист выигрывает за счет того что теперь значительно легко установить новый компонент. К примеру дав интерфейс программисту на стороне, дав ему модульные тесты(в качестве "живого" ТЗ) вы получаете дополнительное время, т.к. пока пилится компонент стороним программером Вы можете пилить другую часть системы, а принять работу можно по прохождению модульных тестов и быть уверенным, что это то что Вы хотели, если конечно хорошо продумали модульные тесты ;)
DI это один из вариантов Inversion of Control. Основная его задача - ресолвить зависимости объектов, больше он ничего не умеет да и не должен. Вам надо создать объект? просите DI. Надо переопределить реализацию интерфейса, на который завязаны ваши классы, не вопрос, поправили в одном месте - применилось везде.
для тестирования важно скорее соблюдение принципа инверсии зависимостей (D в SOLID), а как эти зависимости к нам приходят это уже детали.