У меня есть большая кодовая база с большим количеством «анти-шаблонных» синглетонов, служебных классов со статическими методами и классов, создающих свои собственные зависимости с помощью new
ключевого слова. Это делает код очень сложным для тестирования.
Я хочу постепенно перенести код в контейнер внедрения зависимостей (в моем случае это Guice
потому, что это GWT
проект). Из моего понимания внедрения зависимости это все или ничего. Либо все классы управляются Spring / Guice, либо нет. Поскольку кодовая база велика, я не могу преобразовать код за ночь. Поэтому мне нужен способ сделать это постепенно.
Проблема состоит в том, что когда я начинаю с класса, который нужно внедрить в другие классы, я не могу использовать простой @Inject
в этих классах, потому что эти классы еще не управляются контейнером. Таким образом, это создает длинную цепочку до «верхних» классов, которые нигде не вводятся.
Единственный способ, который я вижу, - сделать Injector
контекст / application глобально доступным через одноэлементное время, чтобы другие классы могли получать из него управляемые bean-компоненты. Но это противоречит важной идее не раскрытия composition root
приложения.
Другой подход будет восходящим: начать с «высокоуровневых» классов, включить их в контейнер внедрения зависимостей и медленно перейти к «меньшим» классам. Но потом мне придется долго ждать, так как я могу тестировать те небольшие классы, которые все еще зависят от глобальных параметров / статики.
Каким был бы способ добиться такой постепенной миграции?
PS Вопрос постепенного подхода к внедрению зависимости похож в заголовке, но он не отвечает на мой вопрос.
Ответы:
Извините
C#
, я выбираю язык, я могу читать,Java
но, вероятно, разбилу синтаксис, пытаясь написать его ... Те же понятия применимы междуC#
иJava
хотя, так что, надеюсь, это покажет шаги в том, как вы могли бы постепенно перемещать свою кодовую базу, чтобы быть более проверяемый.Данный:
может быть легко реорганизован для использования DI без использования контейнера IOC - и вы можете даже разбить его на несколько этапов:
(потенциальный) Шаг первый - взять зависимости, но без изменений в вызывающем (UI) коде:
Рефакторинг 2 (или первый рефакторинг, если реализует контейнер IOC и немедленно изменяет код вызова):
Шаг 2 технически может быть выполнен сам по себе - но (потенциально) будет намного больше работы - в зависимости от того, сколько классов в настоящее время «обновляют» функциональность, которую вы ищете для DI.
Подумайте о переходе с шага 1 -> шаг 2 - вы сможете создавать модульные тесты
Foo
, независимо отBar
. Принимая во внимание, что до рефактора шага 1 это было нелегко осуществить без использования фактической реализации обоих классов. Выполнение шага 1 -> шага 2 (а не шага 2 сразу) позволит со временем вносить меньшие изменения, и у вас уже будет запуск тестового жгута, чтобы обеспечить бесперебойную работу вашего рефакторинга.источник
Концепция одинакова, используете ли вы Java, PHP или даже C #. Этот вопрос довольно хорошо решен Джеммой Аннибл в этом видео на YouTube:
https://www.youtube.com/watch?v=Jccq_Ti8Lck (PHP, извините!)
Вы заменяете непроверяемый код на «фасад» (из-за отсутствия лучшего термина), который вызывает новый тестируемый код. Затем постепенно вы можете заменить старые звонки на подключенные услуги. Я делал это в прошлом, и это работает довольно хорошо.
источник