Kotlin: добавить интерфейс к зависимостям, внедренным guice, чтобы мы могли имитировать их только для целей модульного тестирования?

У меня есть топология шторма, в которой используется guice для введения различных зависимостей в болты. Зависимости не вводятся конструктором из-за проблем сериализации / десериализации шторма. Мы передаем объект guice injector конструктору болта и используем его в методе prepare болта для ввода в поле зависимостей (неидеально, я знаю, но пока не знаю лучшего сценария).

class MyBolt(val injector: Injector) : AbstractRichBolt() {
   @Inject
   @Transient
   private lateinit var myController: MyController
   ...
   override fun prepare(...) {
       this.injector.injectMembers(this)
   }
   override fun execute(input: Tuple) {
       // use myController in our logic here
   }
}

Я пишу модульные тесты для болта с тестовым модулем guice, так что я могу вводить фиктивные зависимости для таких вещей, как контроллеры баз данных и т. д. Для этого мне нужно привязать класс контроллера к фиктивному классу:

bind(MyController::class.java).toInstance(MockController())

Однако, чтобы это работало, мне нужно заставить MockController наследовать тот же интерфейс / суперкласс, что и MyController. В чем я не уверен, так это в том, что добавление интерфейса к MyController только для модульного тестирования является хорошей практикой.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
572
1

Ответы 1

В Kotlin есть функция, позволяющая реализовать функцию как интерфейс. См. https://kotlinlang.org/docs/reference/lambdas.html#instantiating-a-function-type.

class MyController : (Int) -> String {
    override fun invoke(in: Int) : String = "Real Logic"
}

Затем сделайте тестовый двойник с поведением, которое вы хотите в своих тестах.

class StubMyController : (Int) -> String {
    override fun invoke(in: Int) : String = "Test Logic"
}

Затем введите тестовый двойник с помощью инжектора.

bind(MyController::class.java).toInstance(StubMyController())

Вы можете сделать это только один раз за класс. Я использовал эту функцию вместо дополнительных интерфейсов или добавления открытого в класс. Он считает, что это очень поощряет принципы SOLID. Их гораздо больше, но наличие только одного общедоступного метода в классе, безусловно, может помочь сосредоточить внимание на SOLID.

Я понимаю желание сгруппировать связанные методы в один класс, но с Kotlin вы можете получить лучшее из обоих. У вас могут быть очень простые классы с одним общедоступным методом, но сгруппировать эти связанные классы в один файл. Трудно объяснить, почему это может помочь, но это действительно может упростить тестирование и сделать его более читаемым.

Вы также можете использовать mockk https://mockk.io/, чтобы напрямую имитировать зависимости.

Я не знаю, как будет выглядеть функция как интерфейс. Можете показать мне, как это выглядит на моем примере?

breezymri 22.08.2018 23:44

Также у MyController есть несколько методов, которые мне нужно смоделировать. Значит, если я смогу сделать это только один раз, это может не удовлетворить мои потребности?

breezymri 22.08.2018 23:45

Я кратко прочитал документацию по mockK, и она выглядит очень интересно. Тем не менее, все примеры, которые я видел в документе, насмехались над объектом напрямую, а не над косвенным объектом, производным от инжектора guice.

breezymri 22.08.2018 23:50

Другие вопросы по теме